How to Add Timezone into a Naive Datetime Instance in Python

How to make a timezone aware datetime object

In general, to make a naive datetime timezone-aware, use the localize method:

import datetime
import pytz

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)

now_aware = pytz.utc.localize(unaware)
assert aware == now_aware

For the UTC timezone, it is not really necessary to use localize since there is no daylight savings time calculation to handle:

now_aware = unaware.replace(tzinfo=pytz.UTC)

works. (.replace returns a new datetime; it does not modify unaware.)

How to add timezone into a naive datetime instance in python

Use tz.localize(d) to localize the instance. From the documentation:

The first is to use the localize() method provided by the pytz library. This is used to localize a naive datetime (datetime with no timezone information):

>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0))
>>> print(loc_dt.strftime(fmt))
2002-10-27 06:00:00 EST-0500

If you don't use tz.localize(), but use datetime.replace(), chances are that a historical offset is used instead; tz.localize() will pick the right offset in effect for the given date. The US Eastern timezone DST start and end dates have changed over time, for example.

When you try to localize a datetime value that is ambiguous because it straddles the transition period from summer to winter time or vice-versa, the timezone will be consulted to see if the resulting datetime object should have .dst() return True or False. You can override the default for the timezone with the is_dst keyword argument for .localize():

dt = tz.localize(naive, is_dst=True)

or even switch off the choice altogether by setting is_dst=None. In that case, or in the rare cases there is no default set for a timezone, an ambiguous datetime value would lead to a AmbiguousTimeError exception being raised. The is_dst flag is only consulted for datetime values that are ambiguous and is ignored otherwise.

To go back the other way, turn a timezone-aware object back to a naive object, use .replace(tzinfo=None):

naivedt = awaredt.replace(tzinfo=None)

How to add a timezone to a datetime object?

Regarding pytz, note that there is zoneinfo in the standard lib. No need for a third party library for time zone handling with Python >= 3.9. Example usage.

Then, if your input represents wall time in some time zone, you can just localize. If the input represents UTC, you can set the tzinfo to UTC a bit more easily and then convert to local time using astimezone.

from datetime import datetime, timezone
import pytz

s = '20200901-01u30m30s'
local_tz = 'Europe/Amsterdam'

# if s represents local time, just localize:
dtobj_tz = pytz.timezone(local_tz).localize(datetime.strptime(s, '%Y%m%d-%Hu%Mm%Ss'))
# datetime.datetime(2020, 9, 1, 1, 30, 30, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)

# if s represents UTC, set it directly:
dtobj_utc = datetime.strptime(s, '%Y%m%d-%Hu%Mm%Ss').replace(tzinfo=timezone.utc)
# ...and convert to desired tz:
dtobj_tz = dtobj_utc.astimezone(pytz.timezone(local_tz))
# datetime.datetime(2020, 9, 1, 3, 30, 30, tzinfo=<DstTzInfo 'Europe/Amsterdam' CEST+2:00:00 DST>)

In python, how do I create a timezone aware datetime from a date and time?

The trick is to first combine the naive time and the date into a naive datetime. This naive datetime can then be converted to an aware datetime.

The conversion can be done using the third party package pytz (using, in this case, the 'Europe/London' timezone):

import datetime
import pytz

naive_time = datetime.time(0, 30)
date = datetime.date(2016, 12, 25)
naive_datetime = datetime.datetime.combine(date, naive_time)

timezone = pytz.timezone('Europe/London')
aware_datetime = timezone.localize(naive_datetime)

If you're doing it in Django, and want to use the current timezone (as configured in Django), you can replace the final two lines with a call to make_aware:

from django.utils import timezone

aware_datetime = timezone.make_aware(naive_datetime)

Object received a naive datetime (...) while time zone support is active

So you Consumption model probably look alike:

class Consumption(models.Model):
...
accessdate = models.DateField("Fecha de acceso", auto_now=False, auto_now_add=False)
....
addedtime = models.DateTimeField(default=datetime.now()) # this is not timezone aware

replace it with

class Consumption(models.Model):
...
accessdate = models.DateField("Fecha de acceso", auto_now=False, auto_now_add=False)
....
addedtime = models.DateTimeField(auto_now_add=True)

Read your error message carefully! It not speaking about accessdate but about attribute addedtime that probably has some bad default value!

Learn more in https://docs.djangoproject.com/en/3.1/ref/models/fields/#datefield

How do I get a value of datetime.today() in Python that is timezone aware?

In the standard library, there is no cross-platform way to create aware timezones without creating your own timezone class. (Edit: Python 3.9 introduces zoneinfo in the standard library which does provide this functionality.)

On Windows, there's win32timezone.utcnow(), but that's part of pywin32. I would rather suggest to use the pytz library, which has a constantly updated database of most timezones.

Working with local timezones can be very tricky (see "Further reading" links below), so you may rather want to use UTC throughout your application, especially for arithmetic operations like calculating the difference between two time points.

You can get the current date/time like so:

import pytz
from datetime import datetime
datetime.utcnow().replace(tzinfo=pytz.utc)

Mind that datetime.today() and datetime.now() return the local time, not the UTC time, so applying .replace(tzinfo=pytz.utc) to them would not be correct.

Another nice way to do it is:

datetime.now(pytz.utc)

which is a bit shorter and does the same.


Further reading/watching why to prefer UTC in many cases:

  • pytz documentation
  • What Every Developer Should Know About Time – development hints for many real-life use cases
  • The Problem with Time & Timezones - Computerphile – funny, eye-opening explanation about the complexity of working with timezones (video)

Why are these Python datetime conversions affected by local time (UTC offset and DST)?

When you create a datetime object like this:

naive = datetime.datetime(2022,7,7,8,2,34)

You create a naive object (that is not aware of the timezone). Following the documentation:

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.

I think you expect that this object will represent UTC time, but it's not true. It's simply unaware of the timezone so the timezone could be interpreted anyhow.

Let's look at source code of the astimezone method:

def astimezone(self, tz=None):

....

mytz = self.tzinfo
if mytz is None:
mytz = self._local_timezone()
myoffset = mytz.utcoffset(self)
else:

....

# Convert from UTC to tz's local time.
return tz.fromutc(utc)

You see that when self.tzinfo is None then it interprets this as a local timezone rather than UTC

The other examples that you provided are aware of the timezone.



Related Topics



Leave a reply



Submit