Python datetime utcnow does not set timezone? - python

Found this issues working with timestamp conversions where the .timestamp() seem to compensate for time offset even though I created the datetime object with utcnow() method. So what is the reason for the utcnow() method if it actually fails when converting to timestamp later on?
def test_timestamp_issues():
now = datetime.now()
utc_now = datetime.utcnow()
utc_now_with_tz = datetime.now(timezone.utc)
print(f"Now: {now} -- As Timestamp: {now.timestamp()}")
print(f"Utc Now: {utc_now} -- As TimeStamp: {utc_now.timestamp()} "
f"with builtin: {datetime.timestamp(utc_now)}, with setting timezone hard: "
f"{utc_now.replace(tzinfo=timezone.utc).timestamp()}")
print(f"Utc Now: {utc_now_with_tz} -- As TimeStamp: {utc_now_with_tz.timestamp()} "
f"with builtin: {datetime.timestamp(utc_now_with_tz)}, with setting timezone hard: "
f"{utc_now_with_tz.replace(tzinfo=timezone.utc).timestamp()}")
Output:
Now: 2022-04-25 09:12:16.881608 -- As Timestamp: 1650870736.881608
Utc Now: 2022-04-25 07:12:16.881613 -- As TimeStamp: 1650863536.881613 with builtin: 1650863536.881613, with setting timezone hard: 1650870736.881613
Utc Now: 2022-04-25 07:12:16.881753+00:00 -- As TimeStamp: 1650870736.881753 with builtin: 1650870736.881753, with setting timezone hard: 1650870736.881753
The expected timestamp here should be 1650870736.881608 but for some reason converting the utcnow() gives 2 hours backward again.
So for some reason I get another 2 hours withdrawal when taking timestamp of a utcnow() created datetime object. I am currently running a macbook m1 pro, with Timezone Norway (+1, +2 atm with daylight), and python 3.9.12
So can this be the arm architecture messing up things or is it just not recommended to use the utcnow() and then convert to timestamp?

The answer to your question is managing timezones (TZ). When you create a datetime instance with now() or utcnow(), it does not store info about TZ. And, according to python docs for utcnow() (bolding by author):
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. An aware current UTC datetime can be obtained by calling datetime.now(timezone.utc). See also now().
Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).
This means that, although you received time for UTC TZ with utcnow(), since no TZ info is stored (naive datetime object), python thinks of it as a local time. And, when converting it to timestamp, will add/subtract time difference once again. Proof for this weird behaviour may be found in python docs for timestamp() method:
Naive datetime instances are assumed to represent local time
The reason actually is the one, you stated in the title of the question, not the ARM architecture

Related

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

I'm using Python 3.10.4 on Linux trying to convert naive datetime objects that represent UTC to a local time (UTC+1+DST).
What puzzles me is that converting a naive datetime to UTC seems to take the local timezone into consideration despite its tzinfo is None (as it should) - whereas going the other way, i.e. attempting to convert a datetime that is naive or aware (set to UTC) to the local timezone, does not seem to take DST into account.
That only works as expected when using zoneinfo (new in 3.9) instead of timezone.
import datetime
print("naive as UTC")
# naive local time UTC+1 (DST +1)
# -> UTC 22-07-07 06:02:34
naive = datetime.datetime(2022,7,7,8,2,34)
print( naive )
utc = naive.astimezone(datetime.timezone.utc)
print(utc)
print("UTC as local")
utc = datetime.datetime(2022,7,7,8,2,34,tzinfo=datetime.timezone.utc)
print( utc )
tz = datetime.timezone( datetime.timedelta(hours=1) )
local = naive.astimezone(tz)
print(local, local.dst() )
print("UTC as local with zoneinfo")
import zoneinfo
local = utc.astimezone(zoneinfo.ZoneInfo("Europe/Berlin"))
print(local, local.dst() )
Output
naive as UTC
2022-07-07 08:02:34
2022-07-07 06:02:34+00:00
UTC as local
2022-07-07 08:02:34+00:00
2022-07-07 07:02:34+01:00 None
UTC as local with zoneinfo
2022-07-07 10:02:34+02:00 1:00:00
On the other hand, the code for "UTC as local" does seem to handle DST but not the UTC offset:
UTC as local
2022-07-07 08:02:34+00:00
2022-07-07 07:02:34+01:00 None
UTC as local
2022-01-07 08:02:34+00:00
2022-01-07 08:02:34+01:00 None
While I get expected results using zoneinfo, I'd like to understand what is happening with the other "conversions" and why the system clock affects them (running the code on https://www.python.org/shell/ gives different results).
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.
To make a naive datetime object aware, do not use .astimezone(), as that assumes your system's local time for your naive object:
If self is naive, it is presumed to represent time in the system timezone.
Use .replace(tzinfo=...) instead.

timezones in python has couple of minutes shift

from pytz import timezone
import datetime
utc = datetime.timezone.utc
tz = timezone("Europe/London")
now = datetime.datetime.now(utc)
date = now.replace(tzinfo=tz)
date_utc = date.astimezone(utc)
print(now.isoformat())
print(date.isoformat())
print(date_utc.isoformat())
Might print:
2021-12-01T21:30:09.170108+00:00
2021-12-01T21:30:09.170108-00:01 <---- why does it say -00:01 here?
2021-12-01T21:31:09.170108+00:00
Why on earth is there a one minute shift?
Am I missing some fundamental knowledge on time zones?
As per the documentation from PYTZ
Unfortunately using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones.
You can only use localize() or astimezone() to attach PYTZ timezones to datetime objects

Python - how to get the current weekday without using calendar, datetime

I'm having a little bit of a problem here. My system lets me
pip install calendar
but for some reason it doesn't recognize it when importing it in my script.
Whereas for datetime, the module datetime.datetime gives me an error saying that
there is no attribute datetime in datetime.
And datetime.date wants me to feed it a datetime.datetime object, therefore it doesn't let me input strings, lists, ints, or whatever.
Does anyone know another possible way to get the current weekday, or how to fix one of the above?
Thanks
using time.
from time import time, localtime, strftime
x=localtime(time())
strftime("%A",x) # 'Tuesday'
It looks like your most recent errors are caused by the same thing causing the original error with the datetime module.
there is no attribute datetime in datetime.
Is likely the same as the error caused by this line hoursMinsSecs = time.strftime('%H, %M, %S')
These errors are caused because both the datetime and time modules have objects with the same name as the module. (time.time and datetime.datetime). Therefore, how you import the modules or objects becomes very important.
In the time example, your import statement is:
from time import time, localtime, strftime
As a result, the time object has been imported into your namespace and not the time module. Therefore, when you try to run time.strftime('%H, %M, %S') you get an error that strftime isn’t an attribute of the time object.
Instead, since you already imported strftime, just call that directly and do not qualify it with time. (i.e. strftime('%H, %M, %S'))
For your datetime example, you probably had the import statement from datetime import datetime, but somewhere in your code used datetime.datetime

Generating current time in a chosen time zone

I'm trying to perform a, to me, simple task of generating a current date/time combo at a speficic time zone. All I see is suggestions to use pytz even though datetime includes the tzinfo class to deal with timezones. However, if I try to use tzinfo, it does not work:
>>> from datetime import datetime, tzinfo
>>> d = datetime.now(tzinfo.tzname("EDT"))
TypeError: descriptor 'tzname' requires a 'datetime.tzinfo' object but received a 'str'
The docs say you can use a time zone name like "EDT" or "GMT". What's wrong with this?
The function tzinfo.tzname does the opposite of what you think it does.
It takes a datetime object and returns a string indicating the time zone.

What is the point of a naive datetime

Coming from C#, I've learned to always be aware of time-zones when handling date/time. Python has proper timezone handling and useful helpers like datetime.utcnow, which makes working with date/time straight forward. But, when reading in the python docs, I noticed that there is something called a "naive" datetime instance. As far as I can see, this is just a datetime without any timezone.
What is the use-case for a naive datetime?
Isn't a datetime without a time-zone pretty useless?
And why doesn't datetime.now() return a datetime in the current locale (like .NET)?
I'm sure I'm missing something crucial, so I hope someone can shed some light on this.
What is the point of a naive datetime
A naive datetime is very useful!
In some cases you don't know or don't want to specify a timezone.
Imagine that you are parsing an ancient external program log file, and you don't know what timezone the datetimes are in - your best bet is leave them as-is. Attaching a timezone to such datetimes would be wrong and could lead to errors, as you'd be pretending to have information you don't actually have.
And why doesn't datetime.now() return a datetime in the current locale (like .NET)?
datetime.now() does return a value in the current locale timezone, but it doesn't have a timezone associated with it (a tzinfo attribute), which is probably what you meant. Notice that the same is true for utcnow(), both return naive datetimes
The rationale for not including timezone support in the datetime module is alluded to in the docs:
Note that no concrete tzinfo classes are supplied by the datetime module. [...] The rules for time adjustment across the world are more political than rational, and there is no standard suitable for every application.
If you included timezone support in the standard library, you'd get wrong results somewhere in the world.
Timezones are a political concept and change several times a year, globally. The life expectancy of the locally installed python standard library is (generally) much larger than the correctness of timezone data.
What should I do to support timezones
Disclaimer: you should just use UTC in almost all cases. Local timezones should only be used as a last step when showing values to the user.
To use timezones, your program should depend on the pytz package, which gives you proper timezone suport.
from time import tzname
from pytz import timezone
from datetime import datetime
timezone(tzname[0]).localize(datetime.now())
Remember that your program or the local system administrator will need to keep the package up to date.
What is the use-case for a naive datetime?
Python does not allocate space for the pointer to the timezone object if the datetime object is naive:
/* ---------------------------------------------------------------------------
* Basic object allocation: tp_alloc implementations. These allocate
* Python objects of the right size and type, and do the Python object-
* initialization bit. If there's not enough memory, they return NULL after
* setting MemoryError. All data members remain uninitialized trash.
*
* We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo
* member is needed. This is ugly, imprecise, and possibly insecure.
* tp_basicsize for the time and datetime types is set to the size of the
* struct that has room for the tzinfo member, so subclasses in Python will
* allocate enough space for a tzinfo member whether or not one is actually
* needed. That's the "ugly and imprecise" parts. The "possibly insecure"
* part is that PyType_GenericAlloc() (which subclasses in Python end up
* using) just happens today to effectively ignore the nitems argument
* when tp_itemsize is 0, which it is for these type objects. If that
* changes, perhaps the callers of tp_alloc slots in this file should
* be changed to force a 0 nitems argument unless the type being allocated
* is a base type implemented in this file (so that tp_alloc is time_alloc
* or datetime_alloc below, which know about the nitems abuse).
*/
static PyObject *
time_alloc(PyTypeObject *type, Py_ssize_t aware)
{
PyObject *self;
self = (PyObject *)
PyObject_MALLOC(aware ?
sizeof(PyDateTime_Time) :
sizeof(_PyDateTime_BaseTime));
if (self == NULL)
return (PyObject *)PyErr_NoMemory();
PyObject_INIT(self, type);
return self;
}
How you use naive datetime objects is up to you. In my code I use naive datatime objects as:
As if they had UTC timezone associated with them, or
I don't care what the timezone is at all.

Categories