Get a timezone aware datetime with the system timezone in Python - python

How can I get a datetime object that is timezone aware and is in system's timezone?
What I'm trying to do is to get unix time of the 23:59 of the current day.
For example, if I do
int(time.mktime(
datetime.datetime.now(pytz.timezone("Europe/Moscow"))
.replace(hour=23, minute=59, second=59)
.timetuple()
))
I get 1314305999; but when I do $ date -d '#1314305999' in console, I get Fri Aug 26 00:59:59 MSD 2011, which is 1 hour off (DST, perhaps), even though I have Europe/Moscow in /etc/timezone (and the same problem arises if I use such timestamp in PostgreSQL).
And specifying a precise timezone is not really preferable.

Related

Python datetime utcnow vs Luxon Datetime.fromMillis?

I'm trying to wrap my head in understanding the implication of using .utcnow vs. .now on Python's DateTime.
Here's the reason for my confusion: I live in France. Right now, we have a +1 hour on the UTC timezone (CET timezone in winter (now) / CEST (+2) timezone in summer).
If I take the following value :
dt = datetime.datetime.utcnow()
dt.strftime('%c') # Thu Dec 9 16:17:38 2021
int(dt.timestamp()) # 1639063064
This is correct as it is, in France right now, 17h17.
So, from my understanding, that timestamp, 1639063064, is the UTC representation of the time since EPOCH.
But if I test this value in the website Epoch Converter, I get
GMT: Thursday 9 December 2021 15:17:44
Your time zone: jeudi 9 décembre 2021 16:17:44 GMT+01:00
It seems that the website ALSO subtracts my timezone to an already "substracted" value, ending in removing twice the timezone and causing an invalid value.
The actual confusion is when I tried to import that UTC timestamp to Luxon on my front app, doing the following doesn't work :
DateTime.fromMillis(parseInt(ts), { zone: 'utc' }).toLocal().setLocale('en')
I'm one hour behind.
How can I "tell" Luxon that the current TS is in the UTC timezone, and calling toLocal will apply the proper user's timezone ?
It seems that the website ALSO substract my timezone t
No, epochconverter.com isn't doing anything. The value 1639063064 really does represent 2021-12-09T15:17:44Z. That's not the value you want.
I'm no Python expert, but I believe the problem is the combination of this utcnow() behavior (emphasis mine):
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.
And this timestamp() behavior:
Naive datetime instances are assumed to represent local time and this method relies on the platform C mktime() function to perform the conversion.
It sounds like you want to follow this advice:
An aware current UTC datetime can be obtained by calling datetime.now(timezone.utc).
So just change your first line to:
dt = datetime.now(timezone.utc)
... and it should be okay.

Timestamp to non UTC Datetime object is substracting hours twice

I have the following timestamp 1550588656 which translates to 2019-02-19 15:04:16+00:00 in UTC time convention.
I want to convert it to my country's time convention (UTC or GMT -3 in this time of the year) so it should translate to 2019-02-19 12:04:16+00:00
I have read on other SO questions that first I have to convert the timestamp to an UTC aware Datetime object and then localize it, I'm doing it like this
# string format time
naive_datetime = datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
# string parse time
naive_datetime = datetime.strptime(naive_datetime, "%Y-%m-%d %H:%M:%S")
# make naive Datetime object UTC aware
utc_datetime = naive_datetime.replace(tzinfo=pytz.UTC)
So now it's not a naive Datetime object, from here I should be able to localize it to my country's timezone. In Python that is pytz.timezone('America/Santiago')
So it should go something like this
cltime = pytz.timezone('America/Santiago')
local_datetime = utc_datetime.astimezone(cltime)
But I'm getting 2019-02-19 09:04:16-03:00 (UTC or GTM -6 ) as a result and I don't know why.
Can someone explain? My intuition tells me it's probably a simple thing I'm not looking at, but I've spent some minutes in it and I haven't been able to tell yet.
If you look at the documentation for fromtimestamp:
Return the local date and time corresponding to the POSIX timestamp
So the problem is that it is already doing a conversion from UTC to the local time, and you're doing it a second time.
First of all you have epoc time (UTC timestamp). You need to convert it into datetime object (native) which is followed by converting native time to aware time and than finally convert it to your local time.
Convert your timestamp to native datetime object
native_datetime = datetime.fromtimestamp(1550588656)
convert native datetime object to aware time (add timezone info, will add timezone info to native timezone UTC for current)
import pytz
utc_time = native_datetime.replace(tzinfo=pytz.timezone("UTC"))
localising aware datetime to your local datetime
local_time = utc_time.astimezone(pytz.timezone("America/Santiago"))
You can replace "America/Santiago" with your local time zone
I think this would help you to solve your problem. Thanks!

fromtimestamp returns different results

I have the following code:
import datetime
dt = 1546955400
print(datetime.datetime.fromtimestamp(dt))
When I run this code on my local machine, I get the correct (expected) time which is
2019-01-08 15:50:00.
However I tried running this exact same code on a VM and the result was
2019-01-08 13:50:00 (two hours earlier). Why is this is happening and how can I fix it so that I always get the first one regardless of where the code is running?
datetime.datetime.fromtimestamp() returns local time. From the documentation:
Return the local date and time corresponding to the POSIX timestamp, such as is returned by time.time(). If optional argument tz is None or not specified, the timestamp is converted to the platform’s local date and time, and the returned datetime object is naive.
The timestamp value is an offset in seconds from the UNIX epoch value, midnight 1 January 1970, in the UTC timezone. The local time is a system-wide configured offset from UTC, the local timezone.
If your VM is producing unexpected results, you need to configure the timezone of the OS.
Alternatively, ignore timezones and only deal with time in the UTC timezone. For timestamps, that means using the datetime.datetime.utcfromtimestamp() function.
Your specific timestamp is 13:50 UTC:
>>> dt = 1546955400
>>> from datetime import datetime
>>> datetime.utcfromtimestamp(dt)
datetime.datetime(2019, 1, 8, 13, 50)
>>> print(_)
2019-01-08 13:50:00
so your VM is either set to the UTC or the GMT timezone (the latter is currently at UTC+0, until the switch to the UK daylight saving timezone BST). Your local system is in a UTC+2 timezone, given your stated location from your profile that'd be EEE, Easter European Time.
Another option is to create a timezone-aware timestamp by passing in a tz argument. If you have a specific UTC offset, just create a datetime.timezone() instance for that offset:
utcplus2 = datetime.timezone(datetime.timedelta(hours=2))
datetime.datetime.fromtimestamp(dt, utcplus2)
However, it is usually better to store and operate on UTC datetime instances everywhere, and only convert to specific timezones when displaying information to users. This simplifies datetime handling as it lets you avoid a number of timezone corner cases and problems, such as mixing datetime information from different timezones and timezones with a summer and winter time distinction.

Python make datetime offset aware

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))

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