Reputation: 4728
I have data in a file with dates marked, for example, '2015.05.05-11:46', and want to read these lines and then see if they fulfill certain conditions. For example, as input to the function, I may have
get_times('hour', -3.0, -1.2)
which has function defintion:
get_times(unit, start_time, end_time):
which means I want to return all strings that are from -3.0 hours in the past to -1.2 hours in the past. I can get the current time with now = datetime.datetime.now()
. Assuming I read in time1 = '2015.05.05-11:46'
, how do I compare that to now
and find out if it is within start_time
and end_time
unit
s from now?
Upvotes: 0
Views: 4224
Reputation: 414865
To compare time from the file, you should convert it to UTC time (POSIX timestamp) or an aware datetime object (local time + utc offset).
start_time, end_time = get_times('hour', -3, -1.2)
if start_time <= utc_time < end_time:
# utc_time is in between
You should not use start_time <= naive_local_time < end_time
. Convert input time to UTC or create an aware datetime objects instead.
If local times in your input file are consecutive then you could use that fact to disambiguate the timestamps if necessary, see Parsing of Ordered Timestamps in Local Time (to UTC) While Observing Daylight Saving Time.
More explanation and solutions that use time.mktime()
, pytz
, aware datetime objects are in: Find if 24 hrs have passed between datetimes - Python.
datetime.now()
datetime.now()
returns local time as a naive datetime object may be ambiguous e.g., during a DST transition:
>>> from datetime import datetime
>>> import pytz
>>> tz = pytz.timezone('America/New_York')
>>> tz.localize(datetime(2015,11,1,1,30), is_dst=None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/pytz/tzinfo.py", line 349, in localize
raise AmbiguousTimeError(dt)
pytz.exceptions.AmbiguousTimeError: 2015-11-01 01:30:00
>>> tz.localize(datetime(2015,11,1,1,30), is_dst=True).astimezone(pytz.utc)
datetime.datetime(2015, 11, 1, 5, 30, tzinfo=<UTC>)
>>> tz.localize(datetime(2015,11,1,1,30), is_dst=False).astimezone(pytz.utc)
datetime.datetime(2015, 11, 1, 6, 30, tzinfo=<UTC>)
Note: if you remove UTC offset then the same local time may correspond to different UTC time. datetime.utcnow()
is unambiguous (except perhaps during a leap second such as 2015-06-30T23:59:60Z
).
get_times('hour', -3.0, -1.2)
Use UTC time or aware datetime objects:
#!/usr/bin/env python
from datetime import datetime, timedelta
def get_times(unit, relative_start, relative_end):
relative_start, relative_end = [timedelta(**{unit+'s': v})
for v in [relative_start, relative_end]]
now = datetime.utcnow() # or datetime.now(timezone.utc).astimezone()
return now + relative_start, now + relative_end
Upvotes: 0
Reputation: 10417
hope this is what you are looking for:
import datetime
import time
def get_times(unit, start_time, end_time):
now = datetime.datetime.now().timetuple()
matched_dates = []
for date in your_file:
converted_date = time.strptime(date,"%Y.%m.%d-%H:%M")
if converted_date.tm_hour > (now.tm_hour + start_time) and converted_date.tm_hour < (now.tm_hour + end_time):
matched_dates.append(date)
return matched_dates
Upvotes: 1
Reputation: 50630
A couple things need to be done in your situation. First, you need to convert your datetime strings to datetime objects for easy comparison. We do this via strptime
:
input_datetime = datetime.datetime.strptime(i, '%Y.%m.%d-%H:%M')
We also need the function to return start and end times based on your input. If you can make a slight modification and utilize hours
instead of hour
, we can do this without setting up a large if/elif
block.
def get_times(unit, start_time, end_time):
now = datetime.datetime.now()
start_kwarg = {unit: start_time}
end_kwarg = {unit: end_time}
time_start = now + datetime.timedelta(**start_kwarg)
time_end = now + datetime.timedelta(**end_kwarg)
return time_start, time_end
This takes your unit
and creates a dictionary that is passed as a keyword argument to timedelta
. Since hours
is one of the arguments it accepts, we can utilize the keyword instead of mapping hour
to hours
. Then we return start and end time.
Finally, we just need to compare that the input time is between start and end:
start < input_datetime < end
A final script could look like this:
import datetime
def get_times(unit, start_time, end_time):
now = datetime.datetime.now()
start_kwarg = {unit: start_time}
end_kwarg = {unit: end_time}
time_start = now + datetime.timedelta(**start_kwarg)
time_end = now + datetime.timedelta(**end_kwarg)
return time_start, time_end
start, end = get_times('hours', -3.0, -1.2)
input_times = [
'2015.05.12-11:46',
'2014.05.12-11:46',
'2016.05.12-11:46',
'2015.04.12-11:46',
'2015.05.05-11:46'
]
for i in input_times:
input_datetime = datetime.datetime.strptime(i, '%Y.%m.%d-%H:%M')
print "{} => {}".format(input_datetime, start < input_datetime < end)
Output would look like this (if run at 12:46pm on 2015-05-12):
2015-05-12 11:46:00 => True
2014-05-12 11:46:00 => False
2016-05-12 11:46:00 => False
2015-04-12 11:46:00 => False
2015-05-05 11:46:00 => False
Upvotes: 1
Reputation: 11935
Use datetime.strptime to convert your string '2015.05.05-11:46'
then = datetime.datetime.strptime('2015.05.05-11:46', "%Y.%m.%d-%H:%M")
now = datetime.datetime.now()
Then use datetime.timedelta to compare times.
tdelta = now - then
if datetime.timedelta(hours=1.2) < tdelta < datetime.timedelta(hours=3.0):
print "In range"
For writing your function, you'll probably want to stick to the units that are in datetime.timedelta, unless you have a good reason not to.
class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])
So, 'days', 'seconds', 'microseconds', 'milliseconds', 'minutes', 'hours', 'weeks'
Upvotes: 1
Reputation: 59284
You can use <
and >
operators normally.
But for that to work, you have to make all data be datetime
type.
For instance:
time_str = "2015.05.05-11:46"
reference_time = datetime.datetime.strptime(time_str, "%Y.%m.%d-%H:%M")
start_time = reference_time - datetime.timedelta(hours=3)
end_time = reference_time - datetime.timedelta(hours=1.2)
now = datetime.datetime.now()
if end_time <= now <= start_time:
print 'It is in between'
You can also pass arguments to timedelta
function using a dictionary:
>>> a = datetime.timedelta(hours=3, minutes=10)
>>> args = {'hours': 3, 'minutes': 10}
>>> b = datetime.timedelta(**args)
>>> a == b
True
Upvotes: 1