Search code examples
pythondatetimetimestamputc

Python datetime utcnow does not set timezone?


Found this issues working with timestamp conversions where the .timestamp() seem to compensate for time offset even though I created the datetime object with utcnow() method. So what is the reason for the utcnow() method if it actually fails when converting to timestamp later on?

def test_timestamp_issues():
    now = datetime.now()
    utc_now = datetime.utcnow()
    utc_now_with_tz = datetime.now(timezone.utc)
    print(f"Now: {now} -- As Timestamp: {now.timestamp()}")
    print(f"Utc Now: {utc_now} -- As TimeStamp: {utc_now.timestamp()} "
          f"with builtin: {datetime.timestamp(utc_now)}, with setting timezone hard: "
          f"{utc_now.replace(tzinfo=timezone.utc).timestamp()}")
    print(f"Utc Now: {utc_now_with_tz} -- As TimeStamp: {utc_now_with_tz.timestamp()} "
          f"with builtin: {datetime.timestamp(utc_now_with_tz)}, with setting timezone hard: "
          f"{utc_now_with_tz.replace(tzinfo=timezone.utc).timestamp()}")

Output:

Now: 2022-04-25 09:12:16.881608 -- As Timestamp: 1650870736.881608
Utc Now: 2022-04-25 07:12:16.881613 -- As TimeStamp: 1650863536.881613 with builtin: 1650863536.881613, with setting timezone hard: 1650870736.881613
Utc Now: 2022-04-25 07:12:16.881753+00:00 -- As TimeStamp: 1650870736.881753 with builtin: 1650870736.881753, with setting timezone hard: 1650870736.881753

The expected timestamp here should be 1650870736.881608 but for some reason converting the utcnow() gives 2 hours backward again.

So for some reason I get another 2 hours withdrawal when taking timestamp of a utcnow() created datetime object. I am currently running a macbook m1 pro, with Timezone Norway (+1, +2 atm with daylight), and python 3.9.12

So can this be the arm architecture messing up things or is it just not recommended to use the utcnow() and then convert to timestamp?


Solution

  • The answer to your question is managing timezones (TZ). When you create a datetime instance with now() or utcnow(), it does not store info about TZ. And, according to python docs for utcnow() (bolding by author):

    Return the current UTC date and time, with tzinfo None.

    This is like now(), but returns the current UTC date and time, as a naive datetime object. An aware current UTC datetime can be obtained by calling datetime.now(timezone.utc). See also now().

    Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).

    This means that, although you received time for UTC TZ with utcnow(), since no TZ info is stored (naive datetime object), python thinks of it as a local time. And, when converting it to timestamp, will add/subtract time difference once again. Proof for this weird behaviour may be found in python docs for timestamp() method:

    Naive datetime instances are assumed to represent local time

    The reason actually is the one, you stated in the title of the question, not the ARM architecture