You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Document that naïve datetime objects represent local time #91384
Currently, the datetime documentation has this to say about naïve datetimes:
A naive object does not contain enough information to unambiguously locate itself relative to other date/time objects. Whether a naive object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it is up to the program whether a particular number represents metres, miles, or mass. Naive objects are easy to understand and to work with, at the cost of ignoring some aspects of reality.
This was accurate in Python 2.7, but as of Python 3, the picture is a bit more nuanced. .astimezone() and .timestamp() work for naïve datetimes, but they are treated as system local times. It is no longer really appropriate to use a naïve datetime to a datetime in any specific concrete time zone — instead, they should be considered either abstract datetimes for the purposes of calendar calculations, or they should be considered as representing the realization of that abstract datetime in the current system locale. This new behavior is referenced in, for example, the warning in .utcnow(): https://docs.python.org/3.10/library/datetime.html#datetime.datetime.utcnow
There is any number of "systems" that a naïve datetime can refer to: A database value, something received over the wire or read from a file, or indeed, the local time of the computer on which the program is currently running. You cannot know which point in time it refers to or what its timezone is without some sort of out-of-band knowledge. That .astimezone and .timestamp take a guess and use the local time interpretation is not an example to be followed.
The underlying problem is that datetime.now() forgets the origin of the date/time, making it impossible tell the difference between a local time (such as the what now()) returns, and a datetime.datetime() constructed from an external source. I don't think the meaning of naïve datetimes should be changed without a plan for how to address the underlying problem.
@AndersMunch I'm not raising this issue to suggest that we change anything about the nature of datetime, but rather that we document what is currently true about datetime. I do not see any way to fix this "in place" and for a data structure as common and fundamental as datetime I don't think we're likely to be able to migrate to a replacement.
As I noted in my article on the subject, the design that we already have is probably about as good as we can do. We cannot have datetime.now() "remember" that it is a system time because datetime's semantics preclude the creation of a safe "system local time" tzinfo. We should document that the APIs are designed with this in mind — at least it will give people a better mental model for how datetime is going to perform in various situations.
@pganssle but it isn't currently true. For example, DBAPI implementations[1] return naïve datetime's that are not in the current program local time. What they mean depends on context and convention, and quite often that convention will be that database times are UTC, or database server time, or some stipulated "server local time". The one thing it won't be is the system time of whatever database client that is currently connecting, because that would be broken. Naïve datetime's, as found in the wild, don't obey your mental model.
Take care that you distinguish between times that are local in the sense of being an imprecise notation for a single precise point in time, like datetime.now(), and times that are local in the sense of corresponding to multiple different points in time as interpreted by viewpoint: An example of the latter is if I say to you, "you should get up at 5am[2] and see the sunrise" -- in this context 5am means 05:00+02:00 to me, but it might mean 05:00-06:00 to you, and neither is more right than the other. "5am" is not a point in time itself, it's a recipe for how to compute a point in time given additional information. If you declare naïve datetime to be system time then you've outlawed this use.
[1] Not all of them, databases these days have datatypes with timezone information, but I've mostly encountered the other form.
[2] Using "5am" as short for datetime.datetime(2022, 4, 29, 5, 0).
.timestamp and .fromtimestamp treat tz-naive objects as implicitly tzlocal. Everything else does not. The clearest example is dt_naive < dt_aware raising TypeError.
The fundamental problem is not the docs, it iss the inconsistency. A side should be chosen and treatment made consistent across the board. I'd advocate deprecating the timestamp/fromtimestamp behavior.
Activity
pganssle commentedon Apr 5, 2022
Currently, the
datetimedocumentation has this to say about naïve datetimes:This was accurate in Python 2.7, but as of Python 3, the picture is a bit more nuanced.
.astimezone()and.timestamp()work for naïve datetimes, but they are treated as system local times. It is no longer really appropriate to use a naïve datetime to a datetime in any specific concrete time zone — instead, they should be considered either abstract datetimes for the purposes of calendar calculations, or they should be considered as representing the realization of that abstract datetime in the current system locale. This new behavior is referenced in, for example, the warning in.utcnow(): https://docs.python.org/3.10/library/datetime.html#datetime.datetime.utcnowWe make reference to this in the documentation for
.timestamp(): https://docs.python.org/3.10/library/datetime.html#datetime.datetime.timestamp and in.astimezone(): https://docs.python.org/3.10/library/datetime.html#datetime.datetime.astimezone, but the top level explanation makes no reference to it.I have written a blog post about why this is the case: https://blog.ganssle.io/articles/2022/04/naive-local-datetimes.html and made reference to this behavior in an earlier blog post about
utcnow: https://blog.ganssle.io/articles/2019/11/utcnow.html, but I think it would be a good idea to revamp the official documentation to reflect this change in status (12 years or so after the change…)AndersMunch commentedon Apr 25, 2022
There is any number of "systems" that a naïve datetime can refer to: A database value, something received over the wire or read from a file, or indeed, the local time of the computer on which the program is currently running. You cannot know which point in time it refers to or what its timezone is without some sort of out-of-band knowledge. That
.astimezoneand.timestamptake a guess and use the local time interpretation is not an example to be followed.The underlying problem is that
datetime.now()forgets the origin of the date/time, making it impossible tell the difference between a local time (such as the whatnow()) returns, and adatetime.datetime()constructed from an external source. I don't think the meaning of naïve datetimes should be changed without a plan for how to address the underlying problem.pganssle commentedon Apr 25, 2022
@AndersMunch I'm not raising this issue to suggest that we change anything about the nature of
datetime, but rather that we document what is currently true aboutdatetime. I do not see any way to fix this "in place" and for a data structure as common and fundamental asdatetimeI don't think we're likely to be able to migrate to a replacement.As I noted in my article on the subject, the design that we already have is probably about as good as we can do. We cannot have
datetime.now()"remember" that it is a system time becausedatetime's semantics preclude the creation of a safe "system local time"tzinfo. We should document that the APIs are designed with this in mind — at least it will give people a better mental model for howdatetimeis going to perform in various situations.AndersMunch commentedon Apr 28, 2022
@pganssle but it isn't currently true. For example, DBAPI implementations[1] return naïve datetime's that are not in the current program local time. What they mean depends on context and convention, and quite often that convention will be that database times are UTC, or database server time, or some stipulated "server local time". The one thing it won't be is the system time of whatever database client that is currently connecting, because that would be broken. Naïve datetime's, as found in the wild, don't obey your mental model.
Take care that you distinguish between times that are local in the sense of being an imprecise notation for a single precise point in time, like
datetime.now(), and times that are local in the sense of corresponding to multiple different points in time as interpreted by viewpoint: An example of the latter is if I say to you, "you should get up at 5am[2] and see the sunrise" -- in this context 5am means 05:00+02:00 to me, but it might mean 05:00-06:00 to you, and neither is more right than the other. "5am" is not a point in time itself, it's a recipe for how to compute a point in time given additional information. If you declare naïve datetime to be system time then you've outlawed this use.[1] Not all of them, databases these days have datatypes with timezone information, but I've mostly encountered the other form.
[2] Using "5am" as short for
datetime.datetime(2022, 4, 29, 5, 0).jbrockmendel commentedon Sep 24, 2026
This came up on yesterday's pandas dev call.
.timestampand.fromtimestamptreat tz-naive objects as implicitly tzlocal. Everything else does not. The clearest example isdt_naive < dt_awareraising TypeError.The fundamental problem is not the docs, it iss the inconsistency. A side should be chosen and treatment made consistent across the board. I'd advocate deprecating the timestamp/fromtimestamp behavior.
merwok commentedon Sep 24, 2026
Could you find an existing issue for this in the Date and time issues board, or create one if needed, and make your case for deprecation there?
This ticket is about docs only, and a patch would be backported.