Python make datetime offset aware - python

I want to get the offset for datetime and make an aware string.
The following IDLE code works:
Python 3.6.5 (default, Apr 1 2018, 05:46:30)
[GCC 7.3.0] on linux
import datetime
date_now = datetime.datetime.now()
date_now_with_offset = date_now.astimezone()
print(date_now_with_offset)
2018-06-03 17:48:50.258504-05:00
The following code in a script gives an error:
import datetime
date_now = datetime.datetime.now()
date_now_with_offset = date_now.astimezone()
print(date_now_with_offset)
TypeError: Required argument 'tz' (pos 1) not found
I realize that offset and timezone are different but at any given moment
the local time should be offset the same as an accurate timezone offset even though timezone offset may fluctuate during the year.
What is happening and why? What is the best solution?

If a datetime object is missing a timezone you can add it with:
from datetime import datetime, timezone
datetime(1970,1,1).replace(tzinfo=timezone.utc)
or when constructing the datetime object
datetime(1970,1,1).tzinfo==None
# Out: True
datetime(1970,1,1, tzinfo=timezone.utc).tzinfo
# Out: datetime.timezone.utc
timezone is available from version 3.2
I had a similar error with Python 3 when trying to compute the time difference
d = "Tue 01 May 2018 10:34:15 -0000" # date string with timezone
dt = datetime.strptime(d, "%a %d %b %Y %H:%M:%S %z")
dt
# datetime.datetime(2018, 5, 1, 10, 34, 15, tzinfo=datetime.timezone.utc)
dt - datetime(1970,1,1)
# TypeError: can't subtract offset-naive and offset-aware datetimes
Solution: add timezone when creating datetime or modify existing datetime object
dt.tzinfo
# datetime.timezone.utc
dt - datetime(1970,1,1, tzinfo=timezone.utc)
# datetime.timedelta(days=17652, seconds=38055)
# or modify already existing datetime
d_aware = datetime(1970,1,1).replace(tzinfo=timezone.utc)
dt - d_aware
datetime.timedelta(days=17652, seconds=38055)
Define the timezone in your date as needed/according to your knowledge of the missing timezone.
Just a note: datetime(1970,1,1, tzinfo=timezone.utc) is the Epoch time (or POSIX/Unix time) and by definition has UTC timezone.

The script is being executed by the python2 interpreter. Add an explicit python3 shebang to the script:
#! /usr/bin/env python3
import datetime
....

From your traceback: TypeError: Required argument 'tz' (pos 1) not found. Your script is using Python2, which is generally not compatible with Python3. In Python2 you have to provide a timezone. See the difference between the Python2 and Python3 documentation.
In Linux, the python word specifically means python2. Python3 is typed using python3 unless you use an alias. To fix it, change all occurrences of python to python3, as in
#! /usr/bin/env python3
python3 offset.py
Note:
From the Python3 Documentation, it does not work on all versions of Python3:
Changed in version 3.3: tz now can be omitted.
Changed in version 3.6: The astimezone() method can now be called on naive instances that are presumed to represent system local time.`

Overview: you can convert local time to another time zone and display the new time by using astimezone. The astimezone will convert the local time to the timezone datetime. timezone.utc has 0 timezone offset. astimezone changes the clock and the utc offset. astimezone moves the hours and days to match the timezone.
from datetime import datetime, timedelta, timezone
print("Eastern Standard Time Zone")
ET=timezone(timedelta(hours=-5))
dt=datetime(2017,12,30,15,9,3)
print(dt.astimezone(ET))
print("India Standard Time Zone")
IST= timezone(timedelta(hours=5,minutes=30))
dt=datetime(2017,12,30,15,9,3)
print(dt.astimezone(IST))

Related

python: add timezone to time variable TUC to (UTC+2)

Im using docker to deploy. In my code
timestamp = "{:_%Y_%m_%d_%H_%M_%S}".format(datetime.now())
When i printed date of the container used i found that is in UTC.
DOes anyone knows how to modify this row code to add the timezone please ?
to get UTC now, simply use
from datetime import datetime, timezone
timestamp = "{:_%Y_%m_%d_%H_%M_%S}".format(datetime.now(tz=timezone.utc))
no need for an external library.
You are generating datetime object without any timezone info and so is assumed to be in UTC format
You need to pass in the needed timezone to datetime.now() call and adjust the format string to include timezone info
Python >= 3.9
From python 3.9 you have built-in support for timezones with zoneinfo.ZoneInfo class
>>> from zoneinfo import ZoneInfo
>>> tz = ZoneInfo("Europe/London")
>>> timestamp = "{:_%Y_%m_%d_%H_%M_%S %Z}".format(datetime.now(tz))
>>> timestamp
'_2020_08_19_15_26_25 BST'
Python < 3.9
Install pytz (pip install pytz) for timezone support
>>> import pytz
>>> tz = pytz.timezone('Europe/London')
>>> timestamp = "{:_%Y_%m_%d_%H_%M_%S %Z}".format(datetime.now(tz))
>>> timestamp
'_2020_08_18_13_44_22 BST'

Python: strftime a UTC timestamp to local time format

I'd like to use the timestamp from a database result and convert it to my locale time format. The timestamp itself is saved in UTC format: 2015-03-30 07:19:06.746037+02. After calling print value.strftime(format) with the format %d.%m.%Y %H:%M %z the output will be 30.03.2015 07:19 +0200. This might be the correct way to display timestamps with timezone information but unfortunately users here are not accustomed to that. What I want to achieve is the following for the given timestamp: 30.03.2015 09:19. Right now I'm adding two hours via
is_dst = time.daylight and time.localtime().tm_isdst > 0
utc_offset = - (tine.altzone if is_dst else time.timezone)
value = value + timedelta(seconds=utc_offset)
I was wondering if there is a more intelligent solution to my problem. (timestamp.tzinfo has a offset value, can/should this be used instead? The solution needs to be DST aware too.)
In your question the timestamp is already in desired timezone, so you don't need to do anything.
If you want to convert it to some other timezone you should be able to use;
YourModel.datetime_column.op('AT TIME ZONE')('your timezone name')
or,
func.timezone('your timezone name', YourModel.datetime_column)
in SQLAlchemy level.
On python level, consider using pytz
You don't need to do conversions manually when you use time zone aware database timestamps unless the timezone you want to display is different from the system timezone.
When you read and write datetime objects to the database the timezone info of the datetime object is taken into account, this means what you get back is the time in the local time zone, in your case +0200.
This SO post answers how to get local time from a timezoned timestamp.
Basically, use tzlocal.
import time
from datetime import datetime
import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal
# get local timezone
local_tz = get_localzone()
# test it
# utc_now, now = datetime.utcnow(), datetime.now()
ts = time.time()
utc_now, now = datetime.utcfromtimestamp(ts), datetime.fromtimestamp(ts)
local_now = utc_now.replace(tzinfo=pytz.utc).astimezone(local_tz) # utc -> local
assert local_now.replace(tzinfo=None) == now

Python timezone '%z' directive for datetime.strptime() not available

Using '%z' pattern of datetime.strptime()
I have a string text that represent a date and I'm perfectly able to parse it and transform it into a clean datetime object:
date = "[24/Aug/2014:17:57:26"
dt = datetime.strptime(date, "[%d/%b/%Y:%H:%M:%S")
Except that I can't catch the entire date string with the timezone using the %z pattern as specified here
date_tz = 24/Aug/2014:17:57:26 +0200
dt = datetime.strptime(date, "[%d/%b/%Y:%H:%M:%S %z]")
>>> ValueError: 'z' is a bad directive in format '[%d/%b/%Y:%H:%M:%S %z]'
Because as this bug report says
strftime() is implemented per platform
I precise that there is no such a problem with the naive tzinfo directive '%Z'
Workaround : Casting tzinfo string into tzinfo object
I can perfectly make the following workaround by transforming the GST time format string into a tzinfo object [as suggested here][4] using dateutil module
and then insert tzinfo into datetime object
Question: Make %z available for my plateform?
But as I will obviously need %z pattern for further project I would like to find a solution to avoid this workaround and using external module for this simple task.
Can you suggest me some reading on it? I supposed that newer version of python (I'm on 2.7) can handle it but I'd rather not changing my version now for this little but crucial detail.
[EDIT]
Well, seeing comments make me reformulated my question how to parse Email time zone indicator using strptime() without being aware of locale time?
strptime() is implemented in pure Python. Unlike strftime(); it [which directives are supported] doesn't depend on platform. %z is supported since Python 3.2:
>>> from datetime import datetime
>>> datetime.strptime('24/Aug/2014:17:57:26 +0200', '%d/%b/%Y:%H:%M:%S %z')
datetime.datetime(2014, 8, 24, 17, 57, 26, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))
how to parse Email time zone indicator using strptime() without being aware of locale time?
There is no concrete timezone implementation in Python 2.7. You could easily implement the UTC offset parsing, see How to parse dates with -0400 timezone string in python?
In continue to #j-f-sebastians 's answer, here is a fix for python 2.7
Instead of using:
datetime.strptime(t,'%Y-%m-%dT%H:%M %z')
use the timedelta to account for the timezone, like this:
from datetime import datetime,timedelta
def dt_parse(t):
ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M')
if t[17]=='+':
ret-=timedelta(hours=int(t[18:20]),minutes=int(t[20:]))
elif t[17]=='-':
ret+=timedelta(hours=int(t[18:20]),minutes=int(t[20:]))
return ret
print(dt_parse('2017-01-12T14:12 -0530'))
The Answer of Uri is great, saved my life, but when you have
USE_TZ = True you need to be careful with the time, for avoid the warning "RuntimeWarning: DateTimeField" is better if you add the utc to the return.
import pytz
from datetime import datetime, timedelta
def dt_parse(t):
ret = datetime.strptime(t[0:19],'%Y-%m-%dT%H:%M:%S')
if t[23]=='+':
ret-=timedelta(hours=int(t[24:26]), minutes=int(t[27:]))
elif t[23]=='-':
ret+=timedelta(hours=int(t[24:26]), minutes=int(t[27:]))
return ret.replace(tzinfo=pytz.UTC)

Timezone not available in python, but the system timezone is properly set

As specified in the documentation:
%Z -> Time zone name (no characters if no time zone exists).
According to date, my system has the time zone properly set:
gonvaled#pegasus ~ » date
Sat Sep 28 09:14:29 CEST 2013
But this test:
def test_timezone():
from datetime import datetime
dt = datetime.now()
print dt.strftime('%Y-%m-%d %H:%M:%S%Z')
test_timezone()
Produces:
gonvaled#pegasus ~ » python test_timezone.py
2013-09-28 09:19:10
Without time zone information. Why is that? How can I force python to output time zone info?
I have also trying re-configuring the time zone with tzselect, but has not helped.
Standard Python datetime.datetime() objects do not have a timezone object attached to them. The system time is taken as is.
You'll need to install Python timezone support in the form of the pytz package; timezone definitions change too frequently to be bundled with Python itself.
pytz does not tell you what timezone your machine has been configured with. You can use the python-dateutil module for that; it has a dateutil.tz.gettz() function that returns the timezone currently in use. This is much more reliable than what Python can get from the limited C API:
>>> import datetime
>>> from dateutil.tz import gettz
>>> datetime.datetime.now(gettz())
datetime.datetime(2013, 9, 28, 8, 34, 14, 680998, tzinfo=tzfile('/etc/localtime'))
>>> datetime.datetime.now(gettz()).strftime('%Y-%m-%d %H:%M:%S%Z')
'2013-09-28 08:36:01BST'

Python - Setting a datetime in a specific timezone (without UTC conversions)

Just to be clear, this is python 2.6, I am using pytz.
This is for an application that only deals with US timezones, I need to be able to anchor a date (today), and get a unix timestamp (epoch time) for 8pm and 11pm in PST only.
This is driving me crazy.
> pacific = pytz.timezone("US/Pacific")
> datetime(2011,2,11,20,0,0,0,pacific)
datetime.datetime(2011, 2, 11, 20, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:0 STD>)
> datetime(2011,2,11,20,0,0,0,pacific).strftime("%s")
'1297454400'
zsh> date -d '#1297454400'
Fri Feb 11 12:00:00 PST 2011
So, even though I am setting up a timezone, and creating the datetime with that time zone, it is still creating it as UTC and then converting it. This is more of a problem since UTC will be a day ahead when I am trying to do the calculations.
Is there an easy (or at least sensical) way to generate a timestamp for 8pm PST today?
(to be clear, I do understand the value of using UTC in most situations, like database timestamps, or for general storage. This is not one of those situations, I specifically need a timestamp for evening in PST, and UTC should not have to enter into it.)
There are at least two issues:
you shouldn't pass a timezone with non-fixed UTC offset such as "US/Pacific" as tzinfo parameter directly. You should use pytz.timezone("US/Pacific").localize() method instead
.strftime('%s') is not portable, it ignores tzinfo, and it always uses the local timezone. Use datetime.timestamp() or its analogs on older Python versions instead.
To make a timezone-aware datetime in the given timezone:
#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
tz = pytz.timezone("US/Pacific")
aware = tz.localize(datetime(2011, 2, 11, 20), is_dst=None)
To get POSIX timestamp:
timestamp = (aware - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
(On Python 2.6, see totimestamp() function on how to emulate .total_seconds() method).
Create a tzinfo object utc for the UTC time zone, then try this:
#XXX: WRONG (for any timezone with a non-fixed utc offset), DON'T DO IT
datetime(2011,2,11,20,0,0,0,pacific).astimezone(utc).strftime("%s")
Edit: As pointed out in the comments, putting the timezone into the datetime constructor isn't always robust. The preferred method using the pytz documentation would be:
pacific.localize(datetime(2011,2,11,20,0,0,0)).astimezone(utc).strftime("%s")
Also note from the comments that strftime("%s") isn't reliable, it ignores the time zone information (even UTC) and assumes the time zone of the system it's running on. It relies on an underlying C library implementation and doesn't work at all on some systems (e.g. Windows).

Categories

Resources