Check whether input time falls in given time range in python 3 - python

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.

Related

PYTZ always 7 hours ahead

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

Python get total seconds from datetime results in occasional mistakes

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

Elegant way to adjust date timezones in Python

I'm based in the UK, and grappling with summer time BST and timezones.
Here's my code:
TIME_OFFSET = 1 # 0 for GMT, 1 for BST
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
return (datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ') +
datetime.timedelta(hours=TIME_OFFSET)).strftime('%d/%m %H:%M')
Setting a variable like this feels very wrong, but I can't find any elegant way to achieve the above without hideous amounts of code. Am I missing something, and is there no way to (for example) read the system timezone?
To convert UTC to given timezone:
from datetime import datetime
import pytz
local_tz = pytz.timezone("Europe/London") # time zone name from Olson database
def utc_to_local(utc_dt):
return utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
rfc3339s = "2013-04-08T22:35:00Z"
utc_dt = datetime.strptime(rfc3339s, '%Y-%m-%dT%H:%M:%SZ')
local_dt = utc_to_local(utc_dt)
print(local_dt.strftime('%d/%m %H:%M')) # -> 08/04 23:35
See also How to convert a python utc datetime to a local datetime using only python standard library?.
You seem to be asking a few separate questions here.
First, if you only care about your own machine's current local timezone, you don't need to know what it is. Just use the local-to-UTC functions. There are a few holes in the API, but even if you can't find the function you need, you can always just get from local to UTC or vice-versa by going through the POSIX timestamp and the fromtimestamp and utcfromtimestamp methods.
If you want to be able to deal with any timezone, see the top of the docs for the difference between aware and naive objects, but basically: an aware object is one that knows its timezone. So, that's what you need. The problem is that, as the docs say:
Note that no concrete tzinfo classes are supplied by the datetime module. Supporting timezones at whatever level of detail is required is up to the application.
The easiest way to support timezones is to install and use the third-party library pytz.
Meanwhile, as strftime() and strptime() Behavior sort-of explains, strptime always returns a naive object. You then have to call replace and/or astimezone (depending on whether the string was a UTC time or a local time) to get an aware object imbued with the right timezone.
But, even with all this, you still need to know what local timezone you're in, which means you still need a constant. In other words:
TIMEZONE = pytz.timezone('Europe/London')
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
utc_naive = datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ')
utc = utc_naive.replace(pytz.utc)
bst = utc.astimezone(TIMEZONE)
return bst.strftime('%d/%m %H:%M')
So, how do you get the OS to give you the local timezone? Well, that's different for different platforms, and Python has nothing built in to help. But there are a few different third-party libraries that do, such as dateutil. For example:
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
utc = datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ')
bst = utc.astimezone(dateutil.tz.tzlocal())
return bst.strftime('%d/%m %H:%M')
But now we've come full circle. If all you wanted was the local timezone, you didn't really need the timezone at all (at least for your simple use case). So, this is only necessary if you need to support any timezone, and also want to be able to, e.g., default to your local timezone (without having to write two copies of all of your code for the aware and naive cases).
(Also, if you're going to use dateutil in the first place, you might want to use it for more than just getting the timezone—it can basically replacing everything you're doing with both datetime and pytz.)
Of course there are other options besides these libraries—search PyPI, Google, and/or the ActiveState recipes.
If you want to convert a UTC input into a local time, regardless of which timezone you're in, try this:
def utctolocal(input):
if time.localtime()[-1] == 1: st=3600
else: st=0
return time.localtime(time.time()-time.mktime(time.gmtime())+time.mktime(time.localtime(time.mktime(time.strptime(input, '%Y-%m-%dT%H:%M:%SZ'))))+st)
Quite long code, but what it does is it simply adds the difference between time.gmtime() and time.localtime() to the time tuple created from the input.
Here's a function I use to do what I think you want. This assumes that the input is really a gmt, or more precisely, a utc datetime object:
def utc_to_local(utc_dt):
'''Converts a utc datetime obj to local datetime obj.'''
t = utc_dt.timetuple()
secs = calendar.timegm(t)
loc = time.localtime(secs)
return datetime.datetime.fromtimestamp(time.mktime(loc))
Like you said, this relies on the system time zone, which may give you shaky results, as some of the comments have pointed out. It has worked perfectly for me on Windows, however.
A simple function to check if a UCT corresponds to BST in London or GMT (for setting TIME_OFFSET above)
import datetime
def is_BST(input_date):
if input_date.month in range(4,9):
return True
if input_date.month in [11,12,1,2]:
return False
# Find start and end dates for current year
current_year = input_date.year
for day in range(25,32):
if datetime.datetime(current_year,3,day).weekday()==6:
BST_start = datetime.datetime(current_year,3,day,1)
if datetime.datetime(current_year,10,day).weekday()==6:
BST_end = datetime.datetime(current_year,10,day,1)
if (input_date > BST_start) and (input_date < BST_end):
return True
return False

Python datetime subtracting date oddity

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.

How to get UTC time given timezone?

I am in the US and I want to get the UTC time (without the effect of Daylight Saving Time) for a piece of code:
localtime = strftime("%m%d%y%H%M", gmtime())
Right now that code give me time in Greenwich, England. I know that I have a time offset of -8 (GMT -8). How can I get the UTC time to a specific timezone? (using Python library, not casting the hour to integer, - 8, and than convert it back)
Try the datetime module:
datetime.datetime.utcnow() + datetime.timedelta(hours=-8)
BTW, UTC doesn't have timezones, it's Universal Co-ordinated Time, it's the same everywhere.
Just use the localtime() rather than gmtime() function:
localtime = time.strftime("%m%d%y%H%M", time.localtime())
From the python time module:
"Like gmtime() but converts to local time. If secs is not provided or None, the current time as returned by time() is used. The dst flag is set to 1 when DST applies to the given time."
To see if DST applies:
time.daylight
Supporting timezones at whatever level of detail is required is up to the application. The rules for time adjustment across the world are more political than rational, and there is no standard suitable for every application.
There is a useful third party module for that purpose: http://pytz.sourceforge.net/

Categories