18

I have a timezone which is float (for example 4.0).
I want to construct datetime with given timezone.

I tried this,

datetime.now(timezone)

but it throws

TypeError: tzinfo argument must be None or of a tzinfo subclass, not type 'float'

So I wonder how can I make tzinfo from float?

l0gg3r
  • 8,864
  • 3
  • 26
  • 46

5 Answers5

23

If you are using Python 3.2 or newer, you need to create a datetime.timezone() object; it takes an offset as a datetime.timedelta():

from datetime import datetime, timezone, timedelta

timezone_offset = -8.0  # Pacific Standard Time (UTC−08:00)
tzinfo = timezone(timedelta(hours=timezone_offset))
datetime.now(tzinfo)

For earlier Python versions, it'll be easiest to use an external library to define a timezone object for you.

The dateutil library includes objects to take a numerical offset to create a timezone object:

from dateutil.tz import tzoffset

timezone_offset = -8.0  # Pacific Standard Time (UTC−08:00)
tzinfo = tzoffset(None, timezone_offset * 3600)  # offset in seconds
datetime.now(tzinfo)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    Wow, surely there must be a less hard-coded way to go. I'm in the UK: UTC+1 during the "summer" months, but UTC during the others. I want the script to work out which applies automatically. – mike rodent Oct 18 '22 at 18:20
  • @mikerodent: The UK is **not** using UTC in winter, nor `UTC + 1` in summer. The UK uses `BTS` (summer) and `GTM` (winter), respectively, which happen to match `UTC+1` and `UTC` respectively but also define the rules of when they transition from one to the other. If you can use `pytz`, I'd use `Europe/London` and get full summertime / wintertime support. Or use Python 3.9 and the new [`zoneinfo` module](https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo) and the same name. – Martijn Pieters Nov 25 '22 at 17:24
  • @mikerodent: e.g. `datetime(2022, 10, 31, 12, tzinfo=ZoneInfo("Europe/London")).isoformat()` produces `2022-10-31T12:00:00+00:00`, while `datetime(2022, 5, 31, 12, tzinfo=ZoneInfo("Europe/London")).isoformat()` gives `2022-05-31T12:00:00+01:00`, note the offsets in those strings. – Martijn Pieters Nov 25 '22 at 17:32
  • Thanks. But still hard-coded (i.e. the location string), although much better, obviously. See this answer https://stackoverflow.com/a/39079819/595305 (including several of the comments). And also the comment to the question there which says the wish to find the local area automatically is questionable. – mike rodent Nov 25 '22 at 18:12
  • @mikerodent: You didn't mention anything about detecting the local timezone. That's a different problem again, but solvable with platform-specific options; e.g. on Linux just read `/etc/timezone`. The answer there is decent, it gives `GMT` on my Mac, which is perfectly accurate. The `tzlocal` module implements those platform-specific paths (albeit by reading `/etc/localtime` for the definition, which is a symlink to the timezone definition named by `/etc/timezone`; it uses `/etc/timezone` as one of the options to get you the name). On my Mac, again, this produces `Europe/London`. – Martijn Pieters Nov 25 '22 at 22:05
10

I suggest you to use pytz, as it could be simpler.

According to the description:

This library allows accurate and cross platform timezone calculations using Python 2.4 or higher. It also solves the issue of ambiguous times at the end of daylight saving time, which you can read more about in the Python Library Reference

>>> from datetime import datetime
>>> import pytz

>>> datetime.now(tz=pytz.UTC)
datetime.datetime(2021, 11, 12, 20, 59, 54, 579812, tzinfo=<UTC>)

>>> datetime.now(tz=pytz.timezone("Europe/Oslo"))
datetime.datetime(2021, 11, 12, 22, 0, 4, 911480, tzinfo=<DstTzInfo 'Europe/Oslo' CET+1:00:00 STD>)

>>> [tz for tz in pytz.common_timezones if tz.startswith("US")]
['US/Alaska',
 'US/Arizona',
 'US/Central',
 'US/Eastern',
 'US/Hawaii',
 'US/Mountain',
 'US/Pacific']
 

ryanjdillon
  • 17,658
  • 9
  • 85
  • 110
teoreda
  • 2,392
  • 1
  • 21
  • 28
6

One-liner using zoneinfo standard library of Python 3.9:

>>> from zoneinfo import ZoneInfo
>>> datetime.now(ZoneInfo('US/Pacific'))
datetime.datetime(2022, 8, 15, 21, 59, 10, 422603, tzinfo=zoneinfo.ZoneInfo(key='US/Pacific'))
Ash Nazg
  • 514
  • 3
  • 6
  • 14
2

From Python 3.6 onwards you can use the astimezone method on a datetime object to get a timezone-aware datetime object based on the user's locale:

>>> from datetime import datetime

>>> datetime.now().astimezone().isoformat()
'2023-05-25T17:52:38.524753-07:00'
Hans Bouwmeester
  • 1,121
  • 1
  • 17
  • 19
  • Maybe not the answer OP was looking for (seeing that they had the timezone as float), but exactly what I was looking for when I landed here – Harm Jun 17 '23 at 04:47
  • Also: https://docs.python.org/3/library/datetime.html#datetime.datetime.astimezone – Harm Jun 17 '23 at 05:03
1

Python 3.9 brought the IANA tz database support (pytz-like) as zoneinfo.

It's advisable using the IANA names instead of static UTC offsets due daylight saving time.

Yuri
  • 4,254
  • 1
  • 29
  • 46