msg300303 - (view) |
Author: Dave Johansen (Dave Johansen) |
Date: 2017-08-15 17:26 |
This worked in Python 3.6.0 and before:
```
from datetime import datetime
d = datetime(1, 1, 1, 0, 0, 0)
d.timestamp()
```
The error output is:
```
ValueError: year 0 is out of range
```
But it used to return `-62135658000.0`.
Appears to be related to https://bugs.python.org/issue29921
|
msg300338 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2017-08-16 08:58 |
This error is a side effect of the implementation of the PEP 495. In your timezone, datetime(1, 1, 1, 0, 0, 0).timestamp() creates an internal timestamp with year=0. The problem is that the internal function ymd_to_ord() doesn't support year=0:
/* This is incorrect if year <= 0; we really want the floor
* here. But so long as MINYEAR is 1, the smallest year this
* can see is 1.
*/
assert (year >= 1);
> This worked in Python 3.6.0 and before: (...)
The question is if the result was correct before?
|
msg300339 - (view) |
Author: STINNER Victor (vstinner) * |
Date: 2017-08-16 09:01 |
Note: My change was the commit 5b804b2fb0eaa2bacb4afcfe4cfa85b31475e87f which prevented a crash, bpo-29100.
|
msg300389 - (view) |
Author: Dave Johansen (Dave Johansen) |
Date: 2017-08-16 21:13 |
That's a valid `datetime` (i.e. within the min and max values) and `tzinfo` is `None` so I think it's completely reasonable to assume that `timestamp()` will return the correct value.
|
msg300390 - (view) |
Author: Alexander Belopolsky (belopolsky) * |
Date: 2017-08-16 21:44 |
The question is whether -62135658000.0 is the "correct" or even meaningful value:
>>> datetime.utcfromtimestamp(-62135658000.0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: year is out of range
(I ran the above in Python 2.7 to avoid any 3.x datetime innovations.)
I don't see much of a value in allowing datetime.timestamp() to produce values that correspond to out of bounds datetimes in UTC. In most cases this will only result in error later on in the program, or worse an error passing undetected.
What is the use case for datetime.min.timestamp()? I suspect OP encountered this issue in an overly aggressive edge case testing and not in a real user scenario.
|
msg300391 - (view) |
Author: Alexander Belopolsky (belopolsky) * |
Date: 2017-08-16 21:57 |
On the second thought, a reasonable design can use datetime.min/max as placeholders for unknown times far in the past/future compensating for the lack datetime ±inf. In this use case, it may be annoying to see errors from timestamp() instead of some ridiculously large values.
I am -0 on making this change. If anyone is motivated to produce a patch - I'll review it, but I am not going to write it myself.
I am marking this "tests needed" because we need a test complete with setting an appropriate timezone that demonstrates this issue.
|
msg300392 - (view) |
Author: Dave Johansen (Dave Johansen) |
Date: 2017-08-16 22:02 |
The use case was parsing user input of ISO 8601 date strings and converting them to UNIX epochs. The input "0001-01-01T00:00:00" is valid, parses to a valid `datetime` and it seems like a reasonable expectation that all of the functions should work on a valid `datetime` (especially when they worked in earlier versions of Python).
|
msg300393 - (view) |
Author: Dave Johansen (Dave Johansen) |
Date: 2017-08-16 22:30 |
Ok, so I understand the issue now. `timestamp()` for naive datetime instances applies the local timezone offset ( https://docs.python.org/3.6/library/datetime.html#datetime.datetime.timestamp ). This is surprising because naive datetime instances usually are just that and don't make assumptions the timezone, but I guess that the behavior is documented and I was just unaware of it. It still seems like this shouldn't give an error (especially when the timezone of the local machine is UTC), but I guess that it is what it is.
|
msg300394 - (view) |
Author: Alexander Belopolsky (belopolsky) * |
Date: 2017-08-16 22:35 |
It your use case, the input "0001-01-01T00:00:00" was in what timezone?
I suspect what you want is
>>> datetime.min.replace(tzinfo=timezone.utc).timestamp()
-62135596800.0
And not -62135658000.0. If you work with naive datetimes and just want to roundtrip between datetimes and numbers, you should not use a timezone-dependent conversion - attach UTC timezone before calling .timestamp() as shown above. You probably don't want your program to produce different numbers for the same "0001-01-01T00:00:00" input depending on where it is run.
|
msg300395 - (view) |
Author: Alexander Belopolsky (belopolsky) * |
Date: 2017-08-16 22:47 |
BTW, I was originally against introducing .timestamp() method and this issue illustrates why it is problematic: people use it without understanding what it does. If you want the distance between datetime.min and datetime(1970,1,1) in seconds - compute it explicitly:
>>> (datetime.min - datetime(1970,1,1)) / timedelta(0, 1)
-62135596800.0
If you don't want to loose precision is roundtriping between datetimes and numbers - use microseconds:
>>> (datetime.min - datetime(1970,1,1)) // datetime.resolution
-62135596800000000
It is perfectly fine to work with naive datetimes and ignore the timezone issues when all your timestamps are in one timezones, but if you choose to ignore timezones - don't use .timestamp().
|
msg300396 - (view) |
Author: Alexander Belopolsky (belopolsky) * |
Date: 2017-08-16 23:00 |
> It still seems like this shouldn't give an error (especially when the timezone of the local machine is UTC)
This is the part where I agree with you. I suspect the error in the UTC case is an artifact of PEP 495 fold calculations that require probing times ±24 hours around the time being converted. For the times before timezones were invented (late 1800s?) we can safely assume that fold=0 always. To be safe, I would set the fold cut-off at the year 1000.
|
msg385937 - (view) |
Author: delete me (delete_me) |
Date: 2021-01-29 20:56 |
I encountered this issue in Python 3.8. I consider it to be a bug because it's an instance of a class-defined constant (datetime.min) not working with a method of that class (timestamp) when all other values that the class could take work with the method AND the constant works with all of the class' other methods. And it has practical implications: As belopolsky said above, "a reasonable design can use datetime.min/max as placeholders for unknown times far in the past/future compensating for the lack [of] datetime ±inf."
Since datetime.min lies so close to the edges of datetime's value-space, perhaps it should be made offset-aware and placed in UTC so that it stops breaking timestamp() when the user is in the wrong timezone. Alternatively, there could be a note in the documentation for datetime.timestamp() about this edge case. Assuming similarly bizarre behavior happens at datetime.max for one or more datetime methods (and for consistency's sake), it should probably be put in UTC as well.
|
msg397159 - (view) |
Author: Andrei Kulakov (andrei.avk) * |
Date: 2021-07-08 18:00 |
Perhaps min and max should be moved 24 hours up and down respectively? This would make their names more accurately reflect valid range of the class and also allow them to be used as effective -inf +inf.
|
|
Date |
User |
Action |
Args |
2022-04-11 14:58:50 | admin | set | github: 75395 |
2021-07-08 18:00:58 | andrei.avk | set | nosy:
+ andrei.avk messages:
+ msg397159
|
2021-02-01 01:18:02 | chris.jerdonek | set | nosy:
+ chris.jerdonek
|
2021-01-29 20:56:28 | delete_me | set | nosy:
+ delete_me
messages:
+ msg385937 versions:
+ Python 3.8, - Python 3.6 |
2017-08-16 23:00:16 | belopolsky | set | messages:
+ msg300396 |
2017-08-16 22:47:55 | belopolsky | set | messages:
+ msg300395 |
2017-08-16 22:35:51 | belopolsky | set | messages:
+ msg300394 |
2017-08-16 22:30:21 | Dave Johansen | set | messages:
+ msg300393 |
2017-08-16 22:02:30 | Dave Johansen | set | messages:
+ msg300392 |
2017-08-16 21:57:10 | belopolsky | set | messages:
+ msg300391 components:
+ Extension Modules stage: test needed |
2017-08-16 21:44:01 | belopolsky | set | messages:
+ msg300390 |
2017-08-16 21:13:12 | Dave Johansen | set | messages:
+ msg300389 |
2017-08-16 09:01:34 | vstinner | set | messages:
+ msg300339 |
2017-08-16 09:01:02 | vstinner | set | title: min date can't be converted to timestamp -> datetime: min date (0001-01-01 00:00:00) can't be converted to local timestamp |
2017-08-16 08:58:59 | vstinner | set | assignee: vstinner -> belopolsky
messages:
+ msg300338 nosy:
+ belopolsky |
2017-08-16 04:43:40 | rhettinger | set | assignee: vstinner
nosy:
+ vstinner |
2017-08-15 17:26:32 | Dave Johansen | create | |