2

I'm trying to make a function to convert a time string (from the user) to seconds.

what I would like to do is to let the user input the time as a string, like:

"one hour and forty five minutes" 

and then break it down into seconds. So the output from the above will be

6300 seconds
Red
  • 26,798
  • 7
  • 36
  • 58
paolo garrasi
  • 79
  • 2
  • 6
  • what did you tried? – astrick Dec 24 '20 at 12:17
  • 1
    If you are "starting from scratch", you would probably need to write a parser and first you would need to define a grammar describing what the input could be. By the way, in English the number is "forty-five". – Booboo Dec 24 '20 at 12:17
  • 1
    You may find [this](https://stackoverflow.com/questions/493174/is-there-a-way-to-convert-number-words-to-integers) post on converting words to numbers quite helpful. – costaparas Dec 24 '20 at 12:21
  • Check this: [link](https://stackoverflow.com/questions/41355664/how-to-convert-numeric-words-into-numeric-in-python) Or use [word2number](https://pypi.org/project/word2number/) – 4d61726b Dec 24 '20 at 12:25
  • I found a pretty good way to do this (or I think so at least): I just need to take the usual UserInput string and clean it up a little: one hour and forty-five minutes will become one_forty-five; then I'll know that from left to right I'll have H:M:S, convert them to integers with word2number and then do something like this [link](https://stackoverflow.com/questions/6402812/how-to-convert-an-hmmss-time-string-to-seconds-in-python/6402934) – paolo garrasi Dec 24 '20 at 12:51

4 Answers4

1

If you want to do it from scratch then other answers are good. Here's what you can do without typing much:

You need to have word2number installed for this solution.

from word2number import w2n
import re
def strTimeToSec(s):
    s = s.replace(' and', '')
    time = re.split(' hour| hours| minute| minutes| second| seconds', s)[:-1]
    if not('hour' in s):
        time = ['zero']+time
    elif not('minute' in s):
        time = [time[0]]+['zero']+[time[1]]
    elif not('second' in s):
        time = time+['zero']
    time = [w2n.word_to_num(x) for x in time]
    out = time[0]*3600+time[1]*60+time[2]
    return str(out)+' seconds'

>>> print(strTimeToSec('one hour and forty five minute'))

6300 seconds

>>> print(strTimeToSec('one hour forty five minute and thirty three seconds'))

6333 seconds

imraklr
  • 218
  • 3
  • 11
0

This is not an easy task, there is no one certain way you can do that, or I do not know. But I have shared a piece of code that can give you an idea. Firstly you need to read the input string and you need to split it. When you split the data you should search for key strings like an "hour" or "minutes". After this, you need to get this value and search in the dataset where you have already define string versions of the numbers. Then, you need to define some rules, for example (forty, fifty they all finish with ty and you can search these things in the string.)

However, there are infinite possibilities that the user can enter therefore, you should define the limits. I have just shared my opinion on how you can approach this type of problem but I could miss some points.

def convertSeconds(n_hours,n_minutes):
        return n_hours * 3600 + n_minutes *60
    
    dataSet = {
        "one": 1,
        "two": 2,
        "three": 3,
        "four": 4,
        "five": 5,
        "six": 6,
        "seven":7,
        "eight":8,
        "nine":9,
        "hundred":100,
        "hundreds":100,
        "thousand" : 1000,
        "millions" : 1000000
        #etc...
    }
    
    time = input('Please Enter Date As String : ')
    word_array = time.split()
    idx = 0
    idx_hour = 0
    for word in word_array:
        if word == "hour":
            n_hours = word_array[0:idx]
            idx_hour = idx
        if word == "hours":
            n_hours = word_array[0:idx]
            idx_hour = idx
        if word == "and":
            idx_hour = idx_hour +1
        if word == "minute":
            n_minutes = word_array[idx_hour+1:idx]
        if word == "minutes":
            n_minutes = word_array[idx_hour+1:idx]
        idx = idx + 1
    total_hours = 0
    total_minutes = 0
    for counter in range(len(n_hours)):
        value = dataSet[n_hours[counter]]
        if n_hours[counter] == "hundreds" or n_hours[counter] == "hundred":
                 value = dataSet[n_hours[counter-1]] * 100
                 total_hours = total_hours - dataSet[n_hours[counter-1]]
        total_hours = total_hours + value
    
    
    for counter in range(len(n_minutes)):
        value = dataSet[n_minutes[counter]]
        total_minutes = total_minutes + value
    
    print("Your Time in Seconds : ",convertSeconds(total_hours,total_minutes))

Please Enter Date As String : two hundred hours and five minutes
Your Time in Seconds :  720300
Dharman
  • 30,962
  • 25
  • 85
  • 135
Nott
  • 303
  • 1
  • 8
0

The parsedatetime library can do some of the work.

from parsedatetime import Calendar, Constants

c = Calendar(Constants(usePyICU=False))
c.parse("1 minute and 3 hours")

Will return a time structure, unfortunately with whole date included. And if you enter more than 24 hours, a date recalculation will be attempted. And, numbers must be presented as digits, not as words, but you can use replace() to format your string in advance.

Once you have a time structure, you can use time.mktime() to convert it into seconds since Unix, then you can subtract seconds of the current time, or safer, enter the start date in the parse() method and subtract that.

This is imperfect, but I use combination of dateutil.parser.parser.parse() and parsedatetime.Calendar.parse() to get the datetime.datetime() from users. If dateutil fails, then I try with parsedatetime. Users learn how to enter dates and times to get them recognized correctly.

Red
  • 26,798
  • 7
  • 36
  • 58
Dalen
  • 4,128
  • 1
  • 17
  • 35
0

You can do this with a long dictionary of numbers:

def parse_int(string):
    numbers = {'zero': 0,
               'one': 1,
               'two': 2,
               'three': 3,
               'four': 4,
               'five': 5,
               'six': 6,
               'seven': 7,
               'eight': 8,
               'nine': 9,
               'ten': 10,
               'eleven': 11,
               'twelve': 12,
               'thirteen': 13,
               'fourteen': 14,
               'fifteen': 15,
               'sixteen': 16,
               'seventeen': 17,
               'eighteen': 18,
               'nineteen': 19,
               'twenty': 20,
               'twenty-one': 21,
               'twenty-two': 22,
               'twenty-three': 23,
               'twenty-four': 24,
               'twenty-five': 25,
               'twenty-six': 26,
               'twenty-seven': 27,
               'twenty-eight': 28,
               'twenty-nine': 29,
               'thirty': 30,
               'thirty-one': 31,
               'thirty-two': 32,
               'thirty-three': 33,
               'thirty-four': 34,
               'thirty-five': 35,
               'thirty-six': 36,
               'thirty-seven': 37,
               'thirty-eight': 38,
               'thirty-nine': 39,
               'forty': 40,
               'forty-one': 41,
               'forty-two': 42,
               'forty-three': 43,
               'forty-four': 44,
               'forty-five': 45,
               'forty-six': 46,
               'forty-seven': 47,
               'forty-eight': 48,
               'forty-nine': 49,
               'fifty': 50,
               'fifty-one': 51,
               'fifty-two': 52,
               'fifty-three': 53,
               'fifty-four': 54,
               'fifty-five': 55,
               'fifty-six': 56,
               'fifty-seven': 57,
               'fifty-eight': 58,
               'fifty-nine': 59,
               'sixty': 60,
               'sixty-one': 61,
               'sixty-two': 62,
               'sixty-three': 63,
               'sixty-four': 64,
               'sixty-five': 65,
               'sixty-six': 66,
               'sixty-seven': 67,
               'sixty-eight': 68,
               'sixty-nine': 69,
               'seventy': 70,
               'seventy-one': 71,
               'seventy-two': 72,
               'seventy-three': 73,
               'seventy-four': 74,
               'seventy-five': 75,
               'seventy-six': 76,
               'seventy-seven': 77,
               'seventy-eight': 78,
               'seventy-nine': 79,
               'eighty': 80,
               'eighty-one': 81,
               'eighty-two': 82,
               'eighty-three': 83,
               'eighty-four': 84,
               'eighty-five': 85,
               'eighty-six': 86,
               'eighty-seven': 87,
               'eighty-eight': 88,
               'eighty-nine': 89,
               'ninety': 90,
               'ninety-one': 91,
               'ninety-two': 92,
               'ninety-three': 93,
               'ninety-four': 94,
               'ninety-five': 95,
               'ninety-six': 96,
               'ninety-seven': 97,
               'ninety-eight': 98,
               'ninety-nine': 99}
    powers = {'hundred': 10 ** 2,
              'thousand': 10 ** 3,
              'million': 10 ** 6,
              'billion': 10 ** 9,
              'quadrillion': 10 ** 15,
              'quintillion': 10 ** 18,
              'sextillion': 10 ** 21,
              'septillion': 10 ** 24,
              'octillion': 10 ** 27,
              'nonillion': 10 ** 30,
              'decillion': 10 ** 33,
              'undecillion': 10 ** 36,
              'duodecillion': 10 ** 39,
              'tredecillion': 10 ** 42,
              'quattuordecillion': 10 ** 45,
              'quindecillion': 10 ** 48,
              'sexdecillion': 10 ** 51,
              'septemdecillion': 10 ** 54,
              'octodecillion': 10 ** 57,
              'novemdecillion': 10 ** 60,
              'vigintillion': 10 ** 63,
              'vigintunillion': 10 ** 66,
              'unvigintillion': 10 ** 66,
              'duovigintillion': 10 ** 69,
              'vigintiduoillion': 10 ** 69,
              'vigintitrillion': 10 ** 72,
              'trevigintillion': 10 ** 72,
              'vigintiquadrillion': 10 ** 75,
              'quattuorvigintillion': 10 ** 75,
              'quinvigintillion': 10 ** 78,
              'vigintiquintrillion': 10 ** 78,
              'vigintisextillion': 10 ** 81,
              'sexvigintillion': 10 ** 81,
              'vigintiseptillion': 10 ** 84,
              'septvigintillion': 10 ** 84,
              'octovigintillion': 10 ** 87,
              'vigintoctillion': 10 ** 87,
              'vigintinonillion': 10 ** 90,
              'nonvigintillion': 10 ** 90,
              'trigintillion': 10 ** 93,
              'untrigintillion': 10 ** 96,
              'duotrigintillion': 10 ** 99,
              'googol': 10 ** 100,
              'centillion': 10 ** 303}
    
    result = 0
    a = string.split(" ")
    b = []
    
    for c in a:
        if c in numbers:
            b.append(c)
        elif c in powers:
            b[-1] += " " + c
        elif c == "and":
            continue
        else:
            print("INVALID WORD:",c)
            return

    for d, e in enumerate(b):
        if len(e.split(" ")) == 1:
            b[d] = numbers[e]
        else:
            b[d] = e.split(" ")
            b[d][0] = numbers[b[d][0]]
            f = 1
            while f < len(b[d]):
                b[d][f] = powers[b[d][f]]
                f += 1
    
    if not(isinstance(b[0], int)):
       while len(b[0]) > 2:
           b[0][1] *= b[0][2]
           b[0].pop(2)
    
    while len(b):
        if len(b) == 1:
            if isinstance(b[0], int):
                result += b[0]
                b.pop(0)
            else:
                while len(b[0]) > 1:
                    b[0][0] *= b[0][1]
                    b[0].pop(1)
                result += b[0][0]
                b.pop(0)
        else:
            if isinstance(b[1], int):
                b[1] += b[0][0] * b[0][1]
                b.pop(0)
            else:
                while len(b[1]) > 2:
                    b[1][1] *= b[1][2]
                    b[1].pop(2)
                
                if b[0][1] < b[1][1]:
                    b[1][0] += b[0][0] * b[0][1]
                    b.pop(0)
                else:
                    result += b[0][0] * b[0][1]
                    b.pop(0)
    
    return result

hours, minutes = input(">>> ").split(" and ")
seconds = parse_int(hours.rsplit(' ', 1)[0]) * 3600 + \
          parse_int(minutes.rsplit(' ', 1)[0]) * 60
print(seconds)

Test run:

>>> one billion hours and twelve minutes

Output:

3600000000720

Credits: https://codereview.stackexchange.com/a/253014/229550

Red
  • 26,798
  • 7
  • 36
  • 58