This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author p-ganssle
Recipients Yi Luan, belopolsky, p-ganssle
Date 2020-03-16.14:05:08
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1584367508.5.0.772242983407.issue39970@roundup.psfhosted.org>
In-reply-to
Content
@Yi Luan

I think you may misunderstand what the `.timestamp()` function does - it returns an epoch time, which is the amount of time (in seconds) elapsed since the Unix epoch: https://en.wikipedia.org/wiki/Unix_time

The number is not different depending on your time zone:

    >>> from datetime import *
    >>> from dateutil import tz

    >>> dt = datetime(2019, 1, 1, tzinfo=timezone.utc)
    >>> print(f"{dt}: {dt.timestamp()}")
    2019-01-01 00:00:00+00:00: 1546300800.0

    >>> dt = dt.astimezone(tz.gettz("America/New_York"))
    >>> print(f"{dt}: {dt.timestamp()}")
    2018-12-31 19:00:00-05:00: 1546300800.0

    >>> dt = dt.astimezone(tz.gettz("Asia/Tokyo"))
    >>> print(f"{dt}: {dt.timestamp()}")
    2019-01-01 09:00:00+09:00: 1546300800.0

Note how the timestamp number is always the same.

Alexander's suggestion of using `datetime.now(tz=timezone.utc).timestamp()` is slightly misleading because `datetime.now().timestamp()` and `datetime.now(tz=timezone.utc).timestamp()` will always return the same value. I think he was just using that as shorthand for "replace datetime.utcnow() with datetime.now(tz=timezone.utc) in all cases".

When you have a naive datetime (with no tzinfo), the only options are to pick the time zone it represents and convert to UTC or to throw an error and say, "We don't know what time zone this represents, so we cannot do this operation." Python 2 used to throw an exception, but in Python 3 naive datetimes represent local times.

If you want "nominal number of seconds since 1970-01-01T00:00:00 *in this time zone*", you want something more like this:

  def seconds_since(dt, epoch=datetime(1970, 1, 1)):
    return (dt.replace(tzinfo=None) - epoch).total_seconds()

That does not take into account total elapsed time from DST transitions and the like - to do that, you'll want something more like this:

  def seconds_elapsed_since(dt, epoch=datetime(1970, 1, 1)):
    if epoch.tzinfo is None and dt.tzinfo is not None:
        epoch = epoch.replace(tzinfo=dt.tzinfo)
    return (dt - epoch).total_seconds()

I urge you not to do this in any sort of interop protocol, though, because integer timestamps are traditionally interpreted as Unix times, and if you start passing around an integer timestamp that represents "unix time plus or minus a few hours", you are likely to create bugs when someone mistakes it for a unix time.
History
Date User Action Args
2020-03-16 14:05:08p-gansslesetrecipients: + p-ganssle, belopolsky, Yi Luan
2020-03-16 14:05:08p-gansslesetmessageid: <1584367508.5.0.772242983407.issue39970@roundup.psfhosted.org>
2020-03-16 14:05:08p-gansslelinkissue39970 messages
2020-03-16 14:05:08p-gansslecreate