0

Is there any function, in python, that extracts time information from a string to get the time from the current local one? For example:

I have a column with time information in the past compared to the current time (let's say UK time, approximately 20:00)

Time

10 hours # ago
6 hours # ago
12 hours # ago
2 days # ago
1 day # ago

I would like to have, looking at the current UK time, (i.e., approximately 20:00):

New_Time

10:00 
14:00 
8:00
48:00
24:00

The column above comes from the current local time minus the number of hours (from string to numerical) in Time column.

Is it something that I might do with a function? The New_Time is the output that I will need.

In case there might not be a function in python, my approach would be:

  • use something to detect the current time (to save it in a variable)
  • consider hours as 60 min and 1 day as 24 hours ... in order to run some mathematical operations, once transformed strings into numerical
  • subtract from the current time the amount of minutes/hours to go back in time
LdM
  • 674
  • 7
  • 23
  • `df['Time']=df['Time'].apply(lambda x:pd.Timedelta(x))` – Anurag Dabas Apr 10 '21 at 19:04
  • Thanks Anurag. However the formula you suggested just transform string into datetime, so the output is not properly what I would expect (i.e., current local time minus the number of hours reported in the column in my question). I am sorry, I think I explained what I am looking for in a bad way. Trying to edit question – LdM Apr 10 '21 at 19:08
  • Two things why you got downvotes, first it's always a good idea to show some effort, do some research, try something yourself and add that to the question. Second, some might say this is off-topic for SO because asking for a module or package, i.e. ready-to-use code. But people are lazy in general, they don't comment *why* they downvote, although this might be helpful for others. Anyways, don't worry too much about the (down)votes. – FObersteiner Apr 10 '21 at 19:38
  • Thank you so much, MrFuppes. I agree with you. For sure your comment can help me to improve next questions. Much aprpeciated – LdM Apr 11 '21 at 00:04

2 Answers2

1

You can create a method that would return the time that it was a few hours/days/... ago. For example, two methods that will respectively return what day it was x days ago and what hour it was x hours ago :

def getTimeDaysAgo(x):
    today = datetime.datetime.now()
    value = today.day - x
    previousMonth = today.month - 1
    previousMonthDuration = 30
    if previousMonth == 2:
        if today.year % 4 == 0:
            previousMonthDuration = 29
        else:
            previousMonthDuration = 28
    if previousMonth % 2 == 1:
        previousMonthDuration = 31
    return value if value >= 0 else value + previousMonthDuration


def getTimeHoursAgo(x):
    value = datetime.datetime.now().hour - x
    return value if value >= 0 else value + 24

I'm not sure why you want to get "48:00" as a result of 2 days ago and "10:00" as a result of 10 hours ago at the same time. Feel free to ask for more infos, I'd be glad to help you out.

Nephty
  • 140
  • 1
  • 7
  • Well, you don't really need to find it. Or at least I didn't understand it that way. It seems that he wants to get the time x hours ago for example, so you can just specify or ask what time it was 4 hours ago for example, and that's your x. – Nephty Apr 10 '21 at 19:48
  • the confusing thing about the OP's desired output is that it's a mix of time (first three fields) and duration (last two fields)... – FObersteiner Apr 10 '21 at 20:12
  • @Nephty, thank you so much for your answer. I need to get 48 hours and not 2 days as I need to plot these results. But if it would be possible to plot them, even looking at -2days from the time reference, it would be fine. – LdM Apr 11 '21 at 00:05
  • Welcome ! Feel free to ask more questions if you need to, I'd gladly help you out – Nephty Apr 11 '21 at 07:26
  • Hi Nephty, I was thinking of what you said about 48 hours instead of 2 days ago. You were right, as if I want to plot them in order, this could be not possible and it could not make sense with my approach. Thank you for letting me know about your concerns. I am trying to figure it out how to fix it – LdM Apr 11 '21 at 16:33
  • Hey, no problem, it's my pleasure. If you need help with your plotting we can talk in private on Discord or something. – Nephty Apr 12 '21 at 06:56
1

You can make use of the dateparser package (some explanation in comments):

import datetime
import dateparser # pip install dateparser

# a function to format timedelta to string needed below,
# see https://stackoverflow.com/q/538666/10197418
def timedelta2str(sec):
    hours, remainder = divmod(sec, 3600)
    return f'{int(hours):02}:{int(remainder//60):02}'

def formatTimeAgo(string, reftime):
    # try to parser... if successful, you get a datetime object
    dtobj = dateparser.parse(string, settings={'RELATIVE_BASE': reftime})
    if isinstance(dtobj, datetime.datetime):
        # calculate a timedelta object against reference time
        td = reftime - dtobj
        # now format output based on input (days or hours..)
        if td >= datetime.timedelta(1):
            return timedelta2str(td.total_seconds())
        else:
            return (reftime-td).strftime('%H:%M')
    else:
        return "N/A"

# exemplary input
t = ("10 hours", "6 hours", "2 days", "1 day")
# a reference time
reftime = datetime.datetime(2021,4,10,20)
for elem in t:
    print(elem, '->', formatTimeAgo(elem, reftime))
       
# giving you
>>> 10 hours -> 10:00
>>> 6 hours -> 14:00
>>> 2 days -> 48:00
>>> 1 day -> 24:00

Now you can adjust that to be used on pandas.Series:

import pandas as pd

df = pd.DataFrame({'Time': ["10 hours", "6 hours", "12 hours", "2 days", "1 day"]})

df['New_Time'] = df['Time'].apply(formatTimeAgo, args=(reftime,))

df['New_Time']
0    10:00
1    14:00
2    08:00
3    48:00
4    24:00
Name: New_Time, dtype: object
FObersteiner
  • 22,500
  • 8
  • 42
  • 72
  • Hi MrFuppes, I tried to replace `reftime` with `reftime = datetime(int(now.year),int(now.month),int(now.day),int(now.hour))` but it seems that this step `print(elem, '->', formatTimeAgo(elem, reftime))` causes some issue. Do you know, eventually, why? – LdM Apr 11 '21 at 02:23
  • @LdM: if you change the reference time, the output will change of course. Not sure I understand what you mean by "issue" – FObersteiner Apr 11 '21 at 09:28
  • 1
    It was fixed. I just replaced datetime.datetime.now() in the reftime. Thank you, MrFuppes – LdM Apr 11 '21 at 16:23