Since the start and end times of DST in a timezone can change every year, so how does python tell if dst is in effect or not?
At the very top of the CPython source code for the datetime module, it gives the source of the data:
"""Concrete date/time and related types. See
http://www.iana.org/time-zones/repository/tz-link.html for time zone
and DST data sources. """
Presumably this may be variable over time.
Actually my old answer was wrong. In the python shell you can do:
>>> import time
>>>time.localtime()
here it will show a result
>>> _.tm_isdst
This question is actually a duplicate but the old post can be found here:
Python daylight savings time
Related
Why the followings return different timestamp? Is it because datetime.utcnow() doesn't have a timezone? It looks to me that tzinfo=utc is redudant, so I am probably not getting what is utcnow() and how an UTC number could not have a timezone. I guess there is a reason, so please enlight me :)
from datetime import datetime
from pytz import utc
local_seconds = int(datetime.utcnow().timestamp())
utc_seconds = int(datetime.utcnow().replace(tzinfo=utc).timestamp())
My goal is to get the UTC timestamp. It looks like the first method returns the local timestamp (correct me if I am wrong)
EDIT:
Where I live the timezone is GMT-5. In fact:
(utc_seconds-local_seconds)/3600 # is equal to -5.0
Following two statements would always return different result.
local_seconds = int(datetime.utcnow().timestamp())
utc_seconds = int(datetime.utcnow().replace(tzinfo=utc).timestamp())
Output:
1585584790
1585604590
You ask why? Because, by the time first statement executes, there is some time spent during execution and now the second statement would fetch you different result because datetime.utcnow() for 2nd statement has changed.
What I assume is, you want to see if both operations would give the same result or not? They definitely would have given the same results :
Had you provided them the same input?
Had you performed the similar operation from a common library.
To solve 1. change your code like this.
same_time_input = datetime.utcnow()
local_seconds = int(same_time_input.timestamp())
utc_seconds = int(same_time_input.replace(tzinfo=utc).timestamp())
Still the output would not be same, because you are using an external library, and the replace function is not working as you expected.
If you printout the tzinfo from same_time_input, you would see that it doesn't have any timezone info reason of which can be read here. --> Why does datetime.datetime.utcnow() not contain timezone information?
print(same_time_input.tzinfo)
Now, you are trying to give it a timezone info using a separate library which has different implementation internally resulting in slightly off results.
I tried to submit a time var with value of 2016-03-12T01:47:57+00:00 in a timestamp field, it gives me error saying to check the syntax for errors, however when I use a function to normalize the date
t = datetime.datetime.strptime(data['time'], '%Y-%m-%dT%H:%M:%SZ').strftime('%Y-%m-%d:%H:%M:%S')
I get an error like this.
time data '2016-03-12T01:47:57+00:00' does not match format '%Y-%m-%dT%H:%M:%SZ'
What's causing your problem has already been clarified by others, but please allow me to suggest my favorite solution for cases such as yours:
from dateutil import parser
parser.parse(data['time'])
More about the dateutil module here.
There are a few problems here:
The %Z (note the captial Z!) is for time zone, for example GMT. I
think you want the lower case option: %z, which is for UTC offset.
You can read here in the docs what all the options do :)
https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
You need the % symbol before each option. You cannot write %Sz, you must write %S%z. Otherwise Python is trying to match something like 2016-03-12T01:47:57z, rather than 2016-03-12T01:47:57+00:00
Unfortunately, you can't use the %z option with strptime, see this answer:
ISO to datetime object: 'z' is a bad directive
My solution:
It sounds like you don't even want to use the UTC offset. That's fine! If you can't change the way your date string is generated, perhaps this is the best option (though it's maybe a little dirty):
t = datetime.datetime.strptime(data['time'][:-6], '%Y-%m-%dT%H:%M:%S')
This will remove the UTC offset from the string.
If you can change the way your datetime string is being generated, that would be a better solution, but I realise you might not be able to do so.
I hope this helps!
Every time I use:
time.strftime("%z")
I get:
Eastern Daylight Time
However, I would like the UTC offset in the form +HHMM or -HHMM. I have even tried:
time.strftime("%Z")
Which still yields:
Eastern Daylight Time
I have read several other posts related to strftime() and %z always seems to return the UTC offset in the proper +HHMM or -HHMM format. How do I get strftime() to output in the +HHMM or -HHMM format for python 3.3?
Edit: I'm running Windows 7
In 2.x, if you look at the docs for time.strftime, they don't even mention %z. It's not guaranteed to exist at all, much less to be consistent across platforms. In fact, as footnote 1 implies, it's left up to the C strftime function. In 3.x, on the other hand, they do mention %z, and the footnote that explains that it doesn't work the way you'd expect is not easy to see; that's an open bug.
However, in 2.6+ (including all 3.x versions), datetime.strftime is guaranteed to support %z as "UTC offset in the form +HHMM or -HHMM (empty string if the the object is naive)." So, that makes for a pretty easy workaround: use datetime instead of time. Exactly how to change things depends on what exactly you're trying to do — using Python-dateutil tz then datetime.now(tz.tzlocal()).strftime('%z') is the way to get just the local timezone formatted as a GMT offset, but if you're trying to format a complete time the details will be a little different.
If you look at the source, time.strftime basically just checks the format string for valid-for-the-platform specifiers and calls the native strftime function, while datetime.strftime has a bunch of special handling for different specifiers, including %z; in particular, it will replace the %z with a formatted version of utcoffset before passing things on to strftime. The code has changed a few times since 2.7, and even been radically reorganized once, but the same difference is basically there even in the pre-3.5 trunk.
For a proper solution, see abarnert’s answer below.
You can use time.altzone which returns a negative offset in seconds. For example, I’m on CEST at the moment (UTC+2), so I get this:
>>> time.altzone
-7200
And to put it in your desired format:
>>> '{}{:0>2}{:0>2}'.format('-' if time.altzone > 0 else '+', abs(time.altzone) // 3600, abs(time.altzone // 60) % 60)
'+0200'
As abarnert mentioned in the comments, time.altzone gives the offset when DST is active while time.timezone does for when DST is not active. To figure out which to use, you can do what J.F. Sebastian suggested in his answer to a different question. So you can get the correct offset like this:
time.altzone if time.daylight and time.localtime().tm_isdst > 0 else time.timezone
As also suggested by him, you can use the following in Python 3 to get the desired format using datetime.timezone:
>>> datetime.now(timezone.utc).astimezone().strftime('%z')
'+0200'
Use time.timezone to get the time offset in seconds.
Format it using :
("-" if time.timezone > 0 else "+") + time.strftime("%H:%M", time.gmtime(abs(time.timezone)))
to convert the same to +/-HH:MM format.
BTW isn't this supposed to be a bug ? According to strftime docs.
Also I thought this SO answer might help you to convert from Zone offset string to HH:MM format. But since "%z" is not working as expected, I feel its moot.
NOTE: The time.timezone is immune to Daylight savings.
It will come as no surprise that this bug persists in, what is the latest Windows version available currently, Win 10 Version 1703 (Creators). However, time marches on and there is a lovely date-and-time library called pendulum that does what the question asks for. Sébastien Eustace (principal author of the product?) has shown me this.
>>> pendulum.now().strftime('%z')
'-0400'
pendulum assumes UTC/GMT unless told otherwise, and keeps timezone with the date-time object. There are many other possibilities, amongst them these:
>>> pendulum.now(tz='Europe/Paris').strftime('%z')
'+0200'
>>> pendulum.create(year=2016, month=11, day=5, hour=16, minute=23, tz='America/Winnipeg').strftime('%z')
'-0500'
>>> pendulum.now(tz='America/Winnipeg').strftime('%z')
'-0500'
I understand my question title may be a little vague so let me explain.
I need to check to see if an object has gone past a certain date. Now here's what makes it complicated. When the object is added to the model it's only done so with a string date not actually formatted as a date. It's coming from CSV so it's the only way I can do this.
It will always be formatted as M-DD-YY.
Now, what I need to check for is to see if a reset has happened. Resets occur every Wednesday at 4am CEST. So when I'm looking at the model I can have it set as two things.
Expired objects (from the previous reset)
Current objects (that will not reset until next Wednesday)
I really can't figure out the best way to tackle this and I am open to ideas and suggestions.
Thank you.
Convert the field into a datetime in code using dateutil.parser before comparing it to the current date:
from dateutil import parser
from datetime import datetime
object_date = parser.parse(my_obj.datefield)
if object_date < datetime.now():
# Do something
else:
# Do something else
You can install dateutil using pip install python-dateutil
I am trying to have some clever dates since a post has been made on my site ("seconds since, hours since, weeks since, etc..") and I'm using datetime.timedelta difference between utcnow and utc dated stored in the database for a post.
Looks like, according to the docs, I have to use the days attribute AND the seconds attribute, to get the fancy date strings I want.
Can't I just get in whatever time unit I want the value of the entire difference? Am I missing something?
It would be perfect if I could just get the entire difference in seconds.
It seems that Python 2.7 has introduced a total_seconds() method, which is what you were looking for, I believe!
You can compute the difference in seconds.
total_seconds = delta.days * 86400 + delta.seconds
No, you're no "missing something". It doesn't provide deltas in seconds.
It would be perfect if I could just get the entire difference in seconds.
Then plain-old-unix-timestamp as provided by the 'time' module may be more to your taste.
I personally have yet to be convinced by a lot of what's in 'datetime'.
Like bobince said, you could use timestamps, like this:
# assuming ts1 and ts2 are the two datetime objects
from time import mktime
mktime(ts1.timetuple()) - mktime(ts2.timetuple())
Although I would think this is even uglier than just calculating the seconds from the timedelta object...