I have a datetime object created from which I subtract 13 days as follow:
(date.today()-timedelta(days=13)).strftime('%Y-%m-%d')
The strangeness occurs when I execute the code at 6AM and 8:30AM. At 6AM, the resulting string is returned as (if today is 2012-02-29):
2012-02-15
which is 14 days before the current! However, running the same line at 8:30AM, the resulting string is returned as:
2012-02-16
Which then correct. So far I have not been able to figure out what the difference is between the small period of time. I use timezone naive datetime objects, if that is important. I would like to know what could cause this change in the resulting string date.
Many thanks.
EDIT: (based on eumiro's suggestion below)
datetime.datetime.now() returns:
>>> datetime.datetime(2012, 2, 29, 10, 46, 20, 659862)
And the timezone is Europe/Vienna on the server and in the django application that runs the line of code.
I also tried running a similar line to the one you suggested:
(pytz.timezone(settings.TIME_ZONE).localize(datetime.now(), is_dst=True) - \
timedelta(days=13)).strftime('%Y-%m-%d')
But with the same results... which is why I think I don't think it has much to do with timezones also. But at the same time not sure where else to look.
You live somewhere in America? This is the place where the timezones are around 6-8 hours behind the UTC and that's the time of UTC midnight.
What does datetime.datetime.now() return?
If you want to get the real local time, use this (replace "America/New_York" with your timezone):
from datetime import datetime, timedelta
import pytz
now = datetime.datetime.now(pytz.timezone("America/New_York"))
dt = (now - timedelta(days=13)).strftime('%Y-%m-%d')
and it should return the same correct values from midnight until midnight.
Unfortunately DST is poorly supported in Python.
Even pytz is not perfect, but can be made to work with hacks.
You have to decide what it means to subtract 2 days from 10th, 1p.m., either 2 calendar days or 48 hours or 172800 seconds.
Related
Can someone explain to me, how to check whether a given time in "hh:mm" format falls in between a given range.
Say, given time is 10:30 A.M IST and my range is between 10:00 A.M and 11:00 A.M. So given time falls in the range.
Is there any package in python to do this in the easiest way?
Would be happy if anyone can help with this :)
The simple way is just to use datetime.time and compare in an if statement:
import datetime
hhmm = "10:30"
current_time = datetime.datetime.strptime(hhmm, "%H:%M").time()
if datetime.time(10) <= current_time <= datetime.time(11):
print("Time is between 10am and 11am")
else:
print("Time is not between 10am and 11am")
The timezone info is removed from the datetime object when .time() is called on it - if you input a literal time without a timezone, this isn't an issue, while if you do have a timezone then as long as the datetime is transformed (via .astimezone(zoneinfo.ZoneInfo('IST'))) into the timezone you want, you should just be able to compare with the literal 10am and 11am.
See also strptime() behavior, if your input format is more complicated than the above. It's possible to accommodate for AM/PM, as well as timezone.
so I'm trying to make a discord bot in python and make a command that will display all timezones that I choose, but the problem is that all of these timezones are around 7-8 hours ahead of normal.
import datetime
from pytz import timezone
localFormat = "%Y-%m-%d %H:%M:%S, %Z%z"
UTC=datetime.datetime.utcnow()
timezonelist = ["US/Eastern", "US/Central", "US/Mountain", "US/Pacific", "Etc/UTC", "Europe/Berlin", "Australia/North", "Australia/South", "Australia/West"]
for tz in timezonelist:
localDatetime = UTC.astimezone(timezone(tz))
x = localDatetime.strftime(localFormat)
print(tz + " " + x)
for example, Etc/UTC outputs 05:56:25 when it should output 22:56:25, other timezones follow this example, EST outputs 00:56:25 when it should be 17:56:25, or MST (where I am), 22:56:25 instead of 15:56:25. However, datetime.utcnow() returns the correct time.
I had done some research and it said that PYTZ uses the LMT but since all are forward by an amount I do not think it has to do with that.
utcnow() gives you a naive datetime object - it is not aware that it's in UTC although the numbers show UTC. If you convert to another time zone, Python will assume all naive datetime objects are local time. Your local time (MST) is UTC-7, that's why you're off by 7 hours.
The behaviour of utcnow is confusing and can lead to unexpected results - Stop using utcnow and utcfromtimestamp. Instead, use now() and set the tz explicitly:
UTC = datetime.datetime.now(timezone('UTC'))
I'm trying to follow these answers and get the elapsed seconds since Jan 1st 1970 for each element in my array (my_times). I'm then using these values to find the time intervals between each consecutive time. Either approach I take seems to give the wrong answer for at least one pair of times.
Mark Byers answer
To get the seconds since Jan 1st 1970, he suggested to try:
time.mktime(my_time.timetuple())
However this does not seem to work for times "2017-11-05 01:46:00+00" and "2017-11-05 01:47:00+00".
When I run the below code, it says the values are separated by 3660.0 seconds instead of 60.0 seconds
from datetime import datetime
import time
my_time1 = datetime.strptime("2017-11-05 01:46:00+00", "%Y-%m-%d %H:%M:%S+%f")
my_time2 = datetime.strptime("2017-11-05 01:47:00+00", "%Y-%m-%d %H:%M:%S+%f")
time.mktime(my_time2.timetuple()) - time.mktime(my_time1.timetuple())
Andrzej Pronobis' answer
To get the seconds since Jan 1st 1970, he suggested to try:
my_time.timestamp()
This fixed the two earlier times however it no longer works for times "2017-11-05 01:59:00+00" and "2017-11-05 02:00:00+00". The same issue appears, I get 3660.0 seconds instead of 60.0 seconds
from datetime import datetime
my_time1 = datetime.strptime("2017-11-05 01:59:00+00", "%Y-%m-%d %H:%M:%S+%f")
my_time2 = datetime.strptime("2017-11-05 02:00:00+00", "%Y-%m-%d %H:%M:%S+%f")
my_time2.timestamp() - my_time1.timestamp()
I'd like to know if I'm doing anything wrong? Also is there a better way to find all consecutive time intervals when the datetime is given as a String?
Edit:
Thank you John, that fixed the problem. Oddly, changing the format from +%f to %z still ran into the same issue.
What did work was running sudo ln -sf /usr/share/zoneinfo/UTC /etc/localtime (changes my computer's time to UTC) and then evaluating all the times
This is a case of "garbage in, garbage out." Here:
datetime.strptime("2017-11-05 01:59:00+00", "%Y-%m-%d %H:%M:%S+%f")
You probably think that +00 on the end means "UTC time", but the %f format specifier means "fractional seconds."
In any case, you're apparently running on a system where the time zone is set to one with daylight saving time part of the year. 2 AM happens twice on the DST changeover date in November, so your code is working as written (it's ambiguous, basically).
Put another way: your issue is not that you're computing time deltas incorrectly. Your issue is that you are loading the times from strings incorrectly (or ambiguously).
For some reason which I haven't been able to figure out yet, from the the following code:
>>> from pytz import timezone
>>> timezone('America/Chicago')
I get:
<DstTzInfo 'America/Chicago' LMT-1 day, 18:09:00 STD>
When, I assume, I should get:
<DstTzInfo 'America/Chicago' LMT-1 day, 18:00:00 STD>
...since I don't think that my timezone is 6 hours and 9 minutes away from UTC.
I have looked at the source code for pytz but I will admit that I haven't exactly been able to figure out what is going wrong.
I have passed other values to the timezone() function, and the values it returns appear to be correct. For some reason though, the information relevant to my timezone is not correct.
Finally, my co-worker in the cube next to me has confirmed that the function returns the correct timezone info on his machine.
Does anyone have any idea why my timezone ('America/Chicago') would be off by 9 minutes? I am running version 2015.7 of pytz installed using pip. Thank you!
Answer based on the answer by Carl Meyer in Google Groups Answer
The reason for this difference, is that this is NOT the right way of converting a timezone agnostic datetime object to a timezone aware object.
The explanation being:
"A pytz timezone class does not represent a single offset from UTC, it
represents a geographical area which, over the course of history, has
probably gone through several different UTC offsets. The oldest offset
for a given zone, representing the offset from before time zones were
standardized (in the late 1800s, most places) is usually called "LMT"
(Local Mean Time), and it is often offset from UTC by an odd number of
minutes."
(quote from the cited answer in Google Groups)
Basically, you should do:
from datetime import datetime
import pytz
my_datetime = datetime(2015, 6, 11, 13, 30)
my_tz = pytz.timezone('America/Chicago')
good_dt = my_tz.localize(my_datetime)
print(good_dt)
out: 2015-06-11 13:30:00-05:00
Unless your local timezone has a fixed UTC offset then it is pointless to talk about its specific value without providing a specific date/time.
If you provide the time e.g., the current time then you'll see that pytz produces the expected UTC offset:
>>> from datetime import datetime
>>> import pytz
>>> datetime.now(pytz.timezone('America/Chicago')).strftime('%Z%z')
'CST-0600'
See
Datetime Timezone conversion using pytz
pytz localize vs datetime replace
If you don't provide a specific date/time then pytz may return an arbitrary utc offset from the set of available utc offsets for the given timezone. The recent pytz versions return utc offsets that correspond to the earliest time (LMT as a rule) but you should not rely on it. You and your friend may use different pytz versions that may explain the difference in results.
Just because my curiosity wasn't exactly satisfied, I did a little more digging into this problem recently.
Initially, it seemed that the difference stemmed from different versions of pytz. However, after downgrading my version of pytz to a version where I had confirmed that I got a different result from that on my machine, I found that this wasn't the root of the issue: even with the same version of pytz my machine seemed to be using a UTC offset based on LMT, while the other machines were using one based off CDT or CST.
Based on my conversation with #J.F.Sebastian, I assumed that the only other likely possibility was a system level difference. I dug into the pytz source code a little bit more, and found that the file where pytz gets at least some of it's timezone information from is in /usr/share/zoneinfo/. So I looked at the file /usr/share/zoneinfo/America/Chicago and although it is a binary file, part of it is readable. Half way through the file there is a list of timezones: LMTCDTCSTESTCWTCPT. As you can see, LMT is the first name in the list, and as #J.F.Sebastian suggested, that seems to be the one that pytz uses in the situation described in my original question.
That is how the list looks in Ubuntu 15.10. However, in earlier versions of Ubuntu (e.g., Trusty and Precise) where I was getting the result -600 instead of -609 result, the same list is CDTCSTESTCWTCPT.
I will admit that this comes from a lot of blind exploring and half understanding, but it seems like this is what accounts for the differences I was seeing across machines. As far as why the zoneinfo files differ across versions, and what these differences mean for Ubuntu, I have no idea, but I thought I would share my findings for those who are similarly curious, and to potentially receive insightful corrections/supplemental information from the community.
As you mention there are some differences in the original file into the pytz module: (in my case using the Central time)
xxxx......lib/python2.7/site-packages/pytz/zoneinfo/US/Central
In [66]: start = start.replace(tzinfo=central)
In [67]: start.isoformat()
Out[67]: '2018-02-26T00:00:00-05:51'
if you use the standard file of the OS (I tested in mac, ubuntu and centos)
/usr/share/zoneinfo/US/Central
mv xxxx...../lib/python2.7/site-packages/pytz/zoneinfo/US/Central xxxx...../lib/python2.7/site-packages/pytz/zoneinfo/US/Central-bak
ln -s /usr/share/zoneinfo/US/Central xxxx...../lib/python2.7/site-packages/pytz/zoneinfo/US/Central
The problem is resolved
In [7]: central = timezone('US/Central')
In [8]: central
Out[8]: <DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>
In [10]: start = start.replace(tzinfo=central)
In [11]: start.isoformat()
Out[11]: '2018-02-27T00:00:00-06:00'
Totally new to python, I'm actually working on an ex-colleague's script. in looking at it it seems fairly straight-forward. Here's the situation:
The script looks at current localtime (UTC) and renders a time-based table that scrolls/changes throughout the day as the hours pass so there's always a rolling 8 hour table.
The problem is that now we'd like to deploy a copy of this tool (on the same server) in CST ('America/Chicago') (meaning I need to change the UTC time to CST) so I'm just trying to find a way to modify what he has to make the 'current_time' variable == GMT -6.
He used strftime() to get the first hour:
current_time = int(strftime("%H"))
if current_time <19:
temp_page.write(...)
elif current_time == 19:
temp_page.write(...)
etc.
So - from my php knowledge, I'd love to be able to do something like:
current_time = int(strftime("%H"), (localtime() -6 hours))
(yes, I realize that's not real php code, but hopefully you get my meaning ;-))
In my research, I've come across pytz, but this is not installed on the webserver, though I can probably get it if that's the best/easiest way too implement it.
Any help is greatly appreciated.
Yes, try to install pytz, it will help you a lot when working with different timezones (and UTC).
The current UTC time (independent from the timezone of your computer) can be obtained with:
import pytz
from datetime import datetime
now = datetime.now(pytz.utc)
now is now datetime.datetime(2011, 11, 30, 14, 26, 30, 628014, tzinfo=<UTC>) and you can use it to calculate the current UTC hour with now.hour (returns 14)
You could probably use the datetime module (it's part of the standard library, so it's installed if a standard python is on the system).
In particular, datetime objects can have an optional tzinfo attribute, used during timezone conversions. Here's a blog post that explains step-by-step how to use those.