views:

180

answers:

6

I have a file of the following format.

15/07/2010 14:14:13 changed_status_from_Offline_to_Available
15/07/2010 15:01:09 changed_status_from_Available_to_Offline
15/07/2010 15:15:35 changed_status_from_Offline_to_Away became_idle
15/07/2010 15:16:29 changed_status_from_Away_to_Available became_unidle
15/07/2010 15:45:40 changed_status_from_Available_to_Away became_idle
15/07/2010 16:05:40 changed_status_from_Away_to_Available became_unidle
15/07/2010 16:51:39 changed_status_from_Available_to_Offline
20/07/2010 13:07:26 changed_status_from_Offline_to_Available

I need to create a function in python that has to arguments: date and time. It should read the file and return the second status if the date matches and time is less than the time in the function call. That is

Lets say i call the function returnstatus(15/07/2010, 15:10:01). The function should go to the file and return the status of the user on that day at that time, which in this case is "Offline".

I am a Python newbie and any help would be really appreciated.

A: 

I suggest you have a read in the python docs, specifically the time module and the function strptime which can parse textual representation of times into a programmatic representation.

Calling returnstatus the way you wrote in the question will surely fail, you might want to call it with a string representation of the time (i.e. "15/07/2010 15:10:01") or by passing one of the datatypes defined in the time module.

EDIT: obviously if you pass in a string time then finding it in the file is much easier:

if substring in line:
 # do stuff
Yoni H
+1  A: 
import datetime
import time

def lines( path_to_file ):
    '''Open path_to_file and read the lines one at a time, yielding tuples
    ( date of line, time of line, status before line )'''
    with open( path_to_file ) as theFile:
        for line in theFile:
            line = line.rsplit( " ", 1 )
            yield ( 
                datetime.datetime.strptime( line[ 0 ], "%d/%m/%Y %H:%M:%S" ),
                line[ 1 ].split( "_" )[ 3 ]
            )

def return_status( statDate ):
    for lineDate, lineStatus in lines( path_to_file ):
        if statDate > lineDate:
            continue
        return lineStatus

Does that make sense, or would you like me to explain any of it?

Edit

Did you mean what you said above?

date matches and time is less than the time in the function call

In other words, what should happen if you call return_status( 16/07/2010, <some.time> )? Should you get "Offline"?

Another Edit

I have edited it to do sensible datetime comparisons. I think you have read the inequality the wrong way around: we loop through lines in the file until the first line after the date we wish to fetch (keep reading while statDate > lineDate). Once this test fails, line is the first line after the desired date, so its from value is the status at the time we requested. You should call the function with a datetime.datetime.

katrielalex
Actually I didnt get how the numbers come in , that is line [0] line [1] etc
So we open `theFile` and iterate through its lines: `for line in theFile`. Each `line` is now a string, we split it at every space to yield a list of tokens on the line: `line = line.split( " " )`. This makes e.g. `[ '20/07/2010', '13:07:26', 'changed_status_from_Offline_to_Available' ]`. Then `line[ 0 ]` will be the date (still in string format), `line[ 1 ]` the time, and `line[ 3 ]` the status string.
katrielalex
If you import the module `time` then you shouldn't use a variable named `time`.
Ashish
Oopsie. Thanks.
katrielalex
Any reason for the downvotes guys? I'm actually curious, I think this is quite a neat piece of code!
katrielalex
Due to the way you compare dates this wouldn't work if one would like to retrieve the status for this user on 16/07/2010 (which would be Offline). But then again this kind of matching wasn't mentioned in the original question.
Bruce van der Kooij
Well, technically, I've done exactly what he asked: "if the date matches and time is less than the time in the function call"! Otherwise you could just compare the two `datetime`s directly... will edit.
katrielalex
Hello Katie, when i call the function return_status(16/07/2010), it should return "offline". Thanks
Also, i think i havent clarified my question properly. Like when I call return_status(15/7/2010, 15:10:01), it should return the status at that time, which is Offline. From I understand, wouldnt your code return all statuses for all times less than 15:10:01 on 15/7/2010 ?
No, it wouldn't. I think you may have read the inequality backwards? I've updated the post above.
katrielalex
A: 

As Yoni said, you're probably better served by passing a string argument (if you have one). You may also find the types in datetime useful. You'll also want to look into the split function.

Nathon
A: 

Try this:

import datetime

filein = open("filein", "r")

class Status:   
    def __init__(self, date, time, status):
        print date.split('/')
        day, month, year = map(int, date.split('/'))
        hour, minute, second = map(int, time.split(':'))
        self.date_and_time = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second)
        self.status = status

list = []
line = filein.readline().rstrip('\n')

while line != "":
    print line
    date, time, status = line.split(' ')[:3]
    status = status.split('_')
    status.reverse()
    status = status[0]
    status_it = Status(date=date, time=time, status=status)
    line = filein.readline().rstrip('\n')
    list.append(status_it)

def query (date, time):
    day, month, year = map(int, date.split('/'))
    hour, minute, second = map(int, time.split(':'))
    date_and_time = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second)

    for counter, it in enumerate(list):
        if date_and_time >= it.date_and_time and (date_and_time < list[counter + 1].date_and_time or counter == len(list) - 1):
            print it.status
            return
    print "I don't know the status"

query("15/07/2010", "15:10:01")
Teodor Pripoae
-1 Unpythonic and overcomplicated code: You should use `strptime` to parse dates instead of doing it manually. `for line in file` is a clearer way of iterating through a file. `list[-1]` is *much* better than `list.reverse(); list[0]`. You're reading the entire file into memory, bad idea if it's big. `Status` is just a tuple (namedtuple if you must), you don't need a new class for it. All in all, not the right way to do it.
katrielalex
A: 

From the question user392409 most probably wants to pass the parameters as string and wants a single function.

Lets say i call the function returnstatus(15/07/2010, 15:10:01). The function should go to the file and return the status of the user on that day at that time, which in this case is "Offline".

import datetime
import time

def returnstatus(d, t):
    d = datetime.datetime.strptime(d, "%d/%m/%Y")
    t = time.strptime(t, "%H:%M:%S")
    f = open("log.txt")
    for line in f:
        line = line.split(" ")
        line_date = datetime.datetime.strptime(line[0], "%d/%m/%Y")
        line_time = time.strptime(line[1], "%H:%M:%S")
        if d != line_date and t >= line_time:
            continue
        # Returns the first occurrence. To get all store in a list or print.
        f.close()
        return line[2].split("_")[3]
Ashish
@Ashish: this function will almost always return the wrong result (and not just because of the "or" in "if d == line_date or t < line_time").
Bruce van der Kooij
I've changed the `or` to `and` but don't quite follow why it would return the wrong result. Be gentle, haven't had coffee yet. :P
Ashish
@Ashish: :-) try `returnstatus("15/07/2010", "16:51:40")` -- This should return `Offline`, but instead the function incorrectly returns `None`.
Bruce van der Kooij
Now? And what was wrong before? I'm somehow lost and have a feeling I'm gonna feel stupid when someone tells me what I was missing.
Ashish
Hello Ashish, when i am running your code i get the following error, do you know why that could be?returnstatus("15/07/2010","16:51:40")Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> returnstatus("15/07/2010","16:51:40") File "C:/Python27/STstatus.py", line 10, in returnstatus line_date = datetime.datetime.strptime(line[0], "%d/%m/%Y") File "C:\Python27\lib\_strptime.py", line 325, in _strptime (data_string, format))ValueError: time data '\n' does not match format '%d/%m/%Y'>>>
Runs fine for me on Python 3.1.1. Seems you somehow have an extra new line character `\n` somewhere.
Ashish
A: 

Basically, what you need to do is pull out the dates and times from your log into a easy-to-compare format. Enter datetime.

import datetime

def getStatus(log_list, dt, tm):
 #filter the list
 log_list = [a_log_entry for a_log_entry in log_list if a_log_entry[0] == dt and a_log_entry[1] <= tm]

    #sort it
 log_list.sort(cmp=lambda x,y: cmp(x[1], y[1]))
 if log_list is []:
     return 'No status available for this day and time.'

    #pull out the status
 status_to_return = log_list[-1][2].split('_')[-1].strip()

 return status_to_return

if __name__ == '__main__':
 in_file = open('a.log', 'rU')
 a_list = []

 for line in in_file:
  if line.strip() is not '': #handle whitespace
   a_list.append(line.split(' '))

 #convert string dates and times to datetime objects
 a_list = [ [datetime.datetime.strptime(el[0], '%d/%m/%Y'),
    datetime.datetime.strptime(el[1], '%H:%M:%S'), 
    el[2]] for el in a_list]


 a_date = datetime.datetime(2010, 7, 15)
 a_time = datetime.datetime(1900, 1, 1, 16, 1, 0)
 print getStatus(a_list, a_date, a_time)
Chinmay Kanchi
Works well, thanks very much.
I just realised that it will break if there are no entries that match... Changed it to fix...
Chinmay Kanchi