dina
dina

Reputation: 4289

convert timestamp in utc timezone to a given timezone

python version: 3.7

I am trying to convert utc timestamps to a given timezone using pytz and astimezone.

(I have timestamps stored in my db in utc timezone and I amtrynig to convert them)

For example:

here is what I tried:

import pytz

def convert_utc_timestamp_to_timezone(utc_timestamp, dt_timezone):
  return utc_timestamp.astimezone(pytz.timezone(dt_timezone))

expected:

> dt = datetime.datetime.now()
> convert_utc_timestamp_to_timezone(dt, 'UTC') // expected result: dt

but no.., actual result::

> dt = datetime.datetime.now()
> converted = convert_utc_timestamp_to_timezone(dt, 'UTC')
> print(dt) # 2022-07-18 23:10:34.061169
> print(converted) # 2022-07-18 20:10:34.061169+00:00
# dt != converted not as I expect

This works when my local timezone is set to utc - for example when running on online browser

import datetime
import pytz


def convert_utc_timestamp_to_timezone(utc_timestamp, dt_timezone):
  return utc_timestamp.astimezone(pytz.timezone(dt_timezone))
  
dt = datetime.datetime.utcnow()
a = convert_utc_timestamp_to_timezone(dt, 'US/Pacific')

print('in utc timezone',dt)
print('after convert to US/Pacific timezone: ',a)


# results:
#in utc timezone 2022-07-18 20:18:37.253062
# after convert to US/Pacific timezone:  2022-07-18 13:18:37.253062-07:00

dt2 = datetime.datetime.utcnow()
a2 = convert_utc_timestamp_to_timezone(dt, 'UTC')
print('in utc timezone', dt2)
print('after convert to UTC timezone: ',a2)
# results:
# in utc timezone 2022-07-18 20:18:37.264363
# after convert to UTC timezone:  2022-07-18 20:18:37.253062+00:00

But does not work well when running locally - since my pc timezone isn't utc
(the doc actually states that astimezone “converts to local time”)

import pytz
def convert_utc_timestamp_to_timezone(utc_timestamp, dt_timezone):
    return utc_timestamp.astimezone(pytz.timezone(dt_timezone))
dt = datetime.datetime.utcnow()
a = convert_utc_timestamp_to_timezone(dt, 'US/Pacific')
print('in utc timezone', dt)
print('after convert to US/Pacific timezone: ', a)

# result:
# in utc timezone 2022-07-18 20:22:05.526588
# after convert to US/Pacific timezone:  2022-07-18 10:22:05.526588-07:00

dt2 = datetime.datetime.utcnow()
a2 = convert_utc_timestamp_to_timezone(dt, 'UTC')
print('in utc timezone', dt2)
print('after convert to UTC timezone: ', a2)

# result:
# in utc timezone 2022-07-18 20:22:05.576213
# after convert to UTC timezone:  2022-07-18 17:22:05.526588+00:00

what is the correct way to convert timestamp in utc timezone to a given timezone?
I tried pytz localize , but also doesn't give expected result

Upvotes: 0

Views: 294

Answers (2)

Mark Tolonen
Mark Tolonen

Reputation: 178409

Fetch a timezone-aware datetime. Here's an example:

>>> from datetime import datetime
>>> datetime.now()  # timezone unaware, shows my local time
datetime.datetime(2022, 7, 18, 13, 16, 50, 249012)
>>> from datetime import timezone
>>> datetime.now(tz=timezone.utc)  # timezone aware, UTC
datetime.datetime(2022, 7, 18, 20, 17, 28, 760889, tzinfo=datetime.timezone.utc)

Converting from UTC to a particular time zone:

>>> import pytz
>>> now = datetime.now(tz=timezone.utc)
>>> now.astimezone(tz=pytz.timezone('US/Pacific'))
datetime.datetime(2022, 7, 18, 13, 18, 6, 929968, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)

Upvotes: 2

Kache
Kache

Reputation: 16737

This is related to a common gotcha with Python datetime types, kinda due to legacy code reasons. The short answer is that you're mixing timezone aware and timezone un-aware types.

Here's the right way to get a utc timestamp:

In [85]: bad_utc = dt.datetime.utcnow()  # no timezone info
    ...: (bad_utc, bad_utc.astimezone(pytz.utc))
    ...:
Out[85]:
(
  datetime.datetime(2022, 7, 18, 20, 23, 44, 583377),
  datetime.datetime(2022, 7, 19, 3, 23, 44, 583377, tzinfo=<UTC>),
)

In [86]: good_utc = dt.datetime.now(datetime.timezone.utc)  # has timezone info
    ...: (good_utc, good_utc.astimezone(pytz.utc))
    ...:
Out[86]:
(
  datetime.datetime(2022, 7, 18, 20, 23, 47, 323579, tzinfo=datetime.timezone.utc),
  datetime.datetime(2022, 7, 18, 20, 23, 47, 323579, tzinfo=<UTC>),
)

For this reason, there are libraries like pendulum that "do the right thing" and avoid these gotchas, e.g.:

In [79]: dt.datetime.utcnow()  # wrong
Out[79]: datetime.datetime(2022, 7, 18, 20, 20, 41, 681750)

In [80]: dt.datetime.now(datetime.timezone.utc)  # right
Out[80]: datetime.datetime(2022, 7, 18, 20, 20, 45, 947941, tzinfo=datetime.timezone.utc)

In [81]: pendulum.now().utcnow()  # without gotchas
Out[81]: DateTime(2022, 7, 18, 20, 20, 48, 501773, tzinfo=Timezone('UTC'))

Upvotes: 2

Related Questions