- Some DateTime behaviors I just don't understand
I tried: dt = DateTime.DateTime(time.time()) dt.timeTime() and got just what I expected: 915677129.19 I then tried dt = DateTime.DateTime(0.0) dt.timeTime() and got a traceback: Traceback (innermost last): File "<stdin>", line 1, in ? File "DateTime/DateTime.py", line 874, in timeTime raise self.DateTimeError,'No time module compatible time to return' DateTimeError: No time module compatible time to return Surely 0.0 is a valid time module compatible time: time.gmtime(0.0) (1970, 1, 1, 0, 0, 0, 3, 1, 0) Can I not initialize a DateTime object to the Unix epoch? I tried several multiples of 10.0 and didn't avoid the traceback until I tried dt = DateTime.DateTime(100000.0) which is somewhat more than one day more recent than gmtime(0.0). There's apparently some magnitude-dependent interpretation of single numeric initializers, but the documentation file in the package is unclear on how it distinguishes between the two interpretations: A DateTime object is returned that represents either the gmt value of the time.time() float represented in the local machine's timezone, or that number of days after January 1, 1901. Note that the number of days after 1901 need to be expressed from the viewpoint of the local machine's timezone. A negative argument will yield a date-time value before 1901. While horsing around some more, I got some other strange behavior as well: >>> time.gmtime(24*60*60) (1970, 1, 2, 0, 0, 0, 4, 2, 0) >>> dt = DateTime.DateTime(24*60*60) >>> dt.timeTime() 86400 >>> dt = DateTime.DateTime(24*60*50) >>> dt.timeTime() 72000 >>> dt = DateTime.DateTime(24*60*40) >>> dt.timeTime() 57600 >>> dt = DateTime.DateTime(24*60*30.0) Traceback (innermost last): File "<stdin>", line 1, in ? File "DateTime/DateTime.py", line 513, in __init__ s=(_j-int(_j))*86400.0 OverflowError: float too large to convert >>> dt.timeTime() 57600 >>> dt = DateTime.DateTime(24*60*30) Traceback (innermost last): File "<stdin>", line 1, in ? File "DateTime/DateTime.py", line 513, in __init__ s=(_j-int(_j))*86400.0 OverflowError: float too large to convert Why would I be getting overflow errors as the numbers got smaller? Skip Montanaro | Mojam: "Uniting the World of Music" http://www.mojam.com/ skip@calendar.com | Musi-Cal: http://concerts.calendar.com/ 518-372-5583
skip@calendar.com wrote:
I tried:
dt = DateTime.DateTime(time.time()) dt.timeTime()
and got just what I expected:
915677129.19
I then tried
dt = DateTime.DateTime(0.0) dt.timeTime()
and got a traceback:
Traceback (innermost last): File "<stdin>", line 1, in ? File "DateTime/DateTime.py", line 874, in timeTime raise self.DateTimeError,'No time module compatible time to return' DateTimeError: No time module compatible time to return
Surely 0.0 is a valid time module compatible time:
It is, but the DateTime constructor doesn't interpret it as such. It interprets it as the number of days since Jan 1, 1901. Jan 1, 1901 can't be converted to a time time.
time.gmtime(0.0) (1970, 1, 1, 0, 0, 0, 3, 1, 0)
Can I not initialize a DateTime object to the Unix epoch?
Currently, you have to: apply(DateTime,time.gmtime(0)[:6]) or: apply(DateTime,time.localtime(0)[:6])
I tried several multiples of 10.0 and didn't avoid the traceback until I tried
dt = DateTime.DateTime(100000.0)
which is somewhat more than one day more recent than gmtime(0.0).
Right,
There's apparently some magnitude-dependent interpretation of single numeric initializers, but the documentation file in the package is unclear on how it distinguishes between the two interpretations:
A DateTime object is returned that represents either the gmt value of the time.time() float represented in the local machine's timezone, or that number of days after January 1, 1901. Note that the number of days after 1901 need to be expressed from the viewpoint of the local machine's timezone. A negative argument will yield a date-time value before 1901.
Right.
While horsing around some more, I got some other strange behavior as well:
>>> time.gmtime(24*60*60) (1970, 1, 2, 0, 0, 0, 4, 2, 0) >>> dt = DateTime.DateTime(24*60*60) >>> dt.timeTime() 86400 >>> dt = DateTime.DateTime(24*60*50) >>> dt.timeTime() 72000 >>> dt = DateTime.DateTime(24*60*40) >>> dt.timeTime() 57600 >>> dt = DateTime.DateTime(24*60*30.0) Traceback (innermost last): File "<stdin>", line 1, in ? File "DateTime/DateTime.py", line 513, in __init__ s=(_j-int(_j))*86400.0 OverflowError: float too large to convert >>> dt.timeTime() 57600 >>> dt = DateTime.DateTime(24*60*30) Traceback (innermost last): File "<stdin>", line 1, in ? File "DateTime/DateTime.py", line 513, in __init__ s=(_j-int(_j))*86400.0 OverflowError: float too large to convert
Why would I be getting overflow errors as the numbers got smaller?
You don't want to know. ;) The problem is that DateTime wants to support offsets in seconds from the epoc *and* offsets in days from 1901-01-01. This approach is flawed. (It results from some interface baggage from some older date-time implementations of mine.) I'm inclined to change DateTime to only expect epoch offsets in seconds when a single numeric argument is given. This will be changed in the next release. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (540) 371-6909 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
Jim> The problem is that DateTime wants to support offsets in seconds Jim> from the epoc *and* offsets in days from 1901-01-01. This approach Jim> is flawed. (It results from some interface baggage from some older Jim> date-time implementations of mine.) Jim> I'm inclined to change DateTime to only expect epoch offsets in Jim> seconds when a single numeric argument is given. This will be Jim> changed in the next release. Since time.time() returns a float and the number of days since 1901-01-01 would normally be considered an int, why not interpret single floating point args as seconds since the Unix epoch and ints or longs as days since 1901-01-01? This would be easily enough explained in the documentation and would perhaps induce less breakage in existing applications that use DateTime. Skip
On Thu, 7 Jan 1999 skip@calendar.com wrote:
Since time.time() returns a float and the number of days since 1901-01-01 would normally be considered an int, why not interpret single floating point args as seconds since the Unix epoch and ints or longs as days since 1901-01-01? This would be easily enough explained in the documentation and would perhaps induce less breakage in existing applications that use DateTime.
I think this sort of ambiguous contructor overloading is a dangerous practice. Actually, your scheme isn't ambiguous, but it's walking a fine line. ;-) How about a base class with no constuctor arguments, but two setting methods (SetEpoch and SetDays?), and two subclasses which unambiguously deal with each time type? The subclasses would then just be three lines each, and only hanging around for convenience. Only have time for mole hills this week, Mike. -- --- | Mike Pelletier Work: 519-746-1607 /opeware! | Software Developer Home: 519-725-7710 --- | mike@zopeware.com Fax: 519-746-7566 http://www.zopeware.com | Zopeware is not endorsed by Digital Creations
Hmmm... I received two negative replies to my DateTime constructor suggestion almost immediately. Obviously it was not well-received. :-) My original question asked why the behavior of the DateTime constructor was so unobvious in the face of apparently simple initial values like 1. Jim responded and indicated he was going to (I believe) discard the interpretation of small numeric initializers as days since 1901-01-01 in the next release. I looked at that and thought, "Geez, Jim is probably going to have to fix a number of places where DateTime(10) means 1901-01-11." Then I thought there might be a middle ground, and proposed that. It's certainly no worse than the current behavior. Granted, a little weird, but still, unambiguous. I suspect that within the non-Unix world "days since 1901-01-01" is at least as useful a time measurement as "seconds since 1970-01-01:00:00". I'm not much of a database person, but my brief brush with SQL suggests that not having a way to initialize a DateTime using some sort of "days since 1901-01-01" numeric value is going to be a problem. Perhaps it can be tweaked to accept one or more of "%d days" % n "1901-01-01 + %d" % n as valid string initializers. I deal with dates all the time on Musi-Cal, not wide ranges of dates like database folks do, but human meaningful dates like "all of November", "Sept, Oct, Nov", "after July 4th", "June thru September" or "any". Unfortunately, I still have to discard most of those meaningful, unambiguous dates because I don't have time to build and continually tweak the mutha of all date string parsers. I do handle some other obvious ones like "Christmas" and "New Year's Eve", though not "Thanksgiving". Maybe DateTime can evolve into such a mutha. Jim, if you'd like some sample input, I have log files full of dates for you... :-) While I'm daydreaming, I'd like to see DateTime or some other timestamp beast be able to represent relative times like "the next two weeks", so that the absolute value changes depending on when the object is evaluated. That would be the cat's pajamas. Skip Montanaro | Mojam: "Uniting the World of Music" http://www.mojam.com/ skip@calendar.com | Musi-Cal: http://concerts.calendar.com/ 518-372-5583
skip@calendar.com wrote:
Hmmm... I received two negative replies to my DateTime constructor suggestion almost immediately. Obviously it was not well-received. :-)
My original question asked why the behavior of the DateTime constructor was so unobvious in the face of apparently simple initial values like 1. Jim responded and indicated he was going to (I believe) discard the interpretation of small numeric initializers as days since 1901-01-01 in the next release. I looked at that and thought, "Geez, Jim is probably going to have to fix a number of places where DateTime(10) means 1901-01-11."
Nah. This was really meant to allow DateTime(float(d))==d where float(d) returned days. Changing both to use seconds consistently addresses the original need.
Then I thought there might be a middle ground, and proposed that. It's certainly no worse than the current behavior.
True.
Granted, a little weird, but still, unambiguous.
But I think that the proposal to just interpret a single number as a seconds since the epoch is a little better.
I suspect that within the non-Unix world "days since 1901-01-01" is at least as useful a time measurement as "seconds since 1970-01-01:00:00".
Actually, the time.time notion is based on ANSI C's notion of seconds since an epoch, which may not necessarily be 1970.
I'm not much of a database person, but my brief brush with SQL suggests that not having a way to initialize a DateTime using some sort of "days since 1901-01-01" numeric value is going to be a problem. Perhaps it can be tweaked to accept one or more of
"%d days" % n "1901-01-01 + %d" % n
as valid string initializers.
I think that: DateTime(1901,01,01) + days is good enough. This is the current behavior. Note that I have kept the current days units for addition and substraction. This is a little inconsistent, but changing it would break a bunch of existing code. It would be better, in the long run to have a more explicit notion of duration.
I deal with dates all the time on Musi-Cal, not wide ranges of dates like database folks do, but human meaningful dates like "all of November", "Sept, Oct, Nov", "after July 4th", "June thru September" or "any". Unfortunately, I still have to discard most of those meaningful, unambiguous dates because I don't have time to build and continually tweak the mutha of all date string parsers. I do handle some other obvious ones like "Christmas" and "New Year's Eve", though not "Thanksgiving". Maybe DateTime can evolve into such a mutha. Jim, if you'd like some sample input, I have log files full of dates for you... :-)
While I'm daydreaming, I'd like to see DateTime or some other timestamp beast be able to represent relative times like "the next two weeks", so that the absolute value changes depending on when the object is evaluated. That would be the cat's pajamas.
I tend to like this sort of idea, although it tends to get me in trouble. ;) As date parters become more user friendly, they also get to application/local-specific. There should probably be a more modular way to handle date partsing that is separate from the core date-time type. There's something to be said for the approach taken by mxDateTime, which doesn't provide string parsing at all. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (540) 371-6909 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
skip@calendar.com wrote:
Jim> The problem is that DateTime wants to support offsets in seconds Jim> from the epoc *and* offsets in days from 1901-01-01. This approach Jim> is flawed. (It results from some interface baggage from some older Jim> date-time implementations of mine.)
Jim> I'm inclined to change DateTime to only expect epoch offsets in Jim> seconds when a single numeric argument is given. This will be Jim> changed in the next release.
Since time.time() returns a float and the number of days since 1901-01-01 would normally be considered an int,
That was not the intent. You can have fractional days just as easily as fractional seconds.
why not interpret single floating point args as seconds since the Unix epoch and ints or longs as days since 1901-01-01? This would be easily enough explained in the documentation and would perhaps induce less breakage in existing applications that use DateTime.
I don't think that this is going to break any current usage. Note that I'm also changing __int__, __long__, and __float__ to return seconds since the epoch. This will make: DateTime(float(d)) == d In the current implementation, the above expression is true sometimes, false others, and often raises an exception. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (540) 371-6909 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
Just curious, has anybody considered using M A Lemburg's mxDateTime package (http://starship.skyport.net/~lemburg/mxDateTime.html) for dates and times in Zope? It's versatile and relatively mature. No idea what the license is like, but I'll wager it is Zope-compatible. I get the impression that M-A has already dealt with a lot of the issues being discussed. -- Tim Gilbert -:- Tonic Corp -:- tim@tonic.to
Tim Gilbert wrote:
Just curious, has anybody considered using M A Lemburg's mxDateTime package (http://starship.skyport.net/~lemburg/mxDateTime.html) for dates and times in Zope? It's versatile and relatively mature. No idea what the license is like, but I'll wager it is Zope-compatible. I get the impression that M-A has already dealt with a lot of the issues being discussed.
Actually, he punts on a lot of the issues being discussed. :) There is also a significant backward compatability issue for us. There are a bunch of other issues as well. I'd certainly like to use mxDateTime somehow. Maybe a future Zope DateTime facility will be based on it in some fashion. Jim -- Jim Fulton mailto:jim@digicool.com Technical Director (540) 371-6909 Python Powered! Digital Creations http://www.digicool.com http://www.python.org Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email address may not be added to any commercial mail list with out my permission. Violation of my privacy with advertising or SPAM will result in a suit for a MINIMUM of $500 damages/incident, $1500 for repeats.
participants (4)
-
Jim Fulton -
Mike Pelletier -
skip@calendar.com -
Tim Gilbert