I'm working on a Python script that will read a file and grab a string total_time. Currently, this is what I have.
if("Total time" in data):
total_time=int(filter(str.isdigit, data))
print(total_time)
Output: 419
I'm trying to find the best way to read lots of files, grab this total time, and convert 419 into 4 hours and 19 minutes to allow me to do some statics and analytics with this.
Passing format argument to datetime in Pandas:
t="419"
a = pd.to_datetime(t, format='%H%M')
print(a.hour)
print(a.minute)
The built-in function divmod() seems appropriate here!
>>> a = 5
>>> b = 3
>>> divmod(a,b) # (a // b, a % b)
(1,2)
For your specific situation:
def dataToTime(data):
''' Returns a list of (hour, minute) tuples from
a list of strings '''
total_times = filter(str.isdigit,data)
return [divmod(int(time),100) for time in total_times]
If you would like to parse the data as you are inputting it try the re module which has the method re.sub() for regex substitution
>>> import re
>>> s = '| Total time | 4:19 | | |--------------+--------+------| –'
>>> h = int(re.sub(r':.*$|[^0-9]','',s))
>>> m = int(re.sub(r'^.*:|[^0-9]','',s))
>>> print h,m
(4,19)
Given some string set as
s = '419'
you can get the upper and lower digits by converting to an integer, then using modulo and integer division. The integer conversion can be encapsulated in a try-except block catching ValueError if you have a reasonable response to invalid inputs:
n = int(s)
hours = n // 100 # Truncating integer division
minutes = n % 100 # Modulo removes the upper digits
Related
I am successfully able to read back data from an instrument:
When the read back is a voltage, I typically read back values such as 5.34e-02 Volts.
When the read back is frequency, I typically read values like 2.95e+04or 1.49e+05 with units Hz.
I would like to convert the voltage read back of 5.34e-02 to exponent e-3 (aka millivolts), ie.. 53.4e-3. next, I would like to extract the mantissa 53.4 out of this because I want all my data needs to be in milliVolts.
Similarly, I would like to convert all the frequency such as 2.95e+04 (or 1.49e+05) to kiloHz, ie... 29.5e+03 or 149e+03. Next would like to extract the mantissa 29.5 and 149 from this since all my data needs to be kHz.
Can someone suggest how to do this?
Well, to convert volts to millivolts, you multiply by 1000. To convert Hz to kHz, you divide by 1000.
>>> reading = 5.34e-02
>>> millivolts = reading * 1000
>>> print(millivolts)
53.400000000000006
>>> hz = 2.95e+04
>>> khz = hz /1000
>>> khz
29.5
>>>
FOLLOW-UP
OK, assuming your real goal is to keep the units the same but adjust the exponent to a multiple of 3, see if this meets your needs.
def convert(val):
if isinstance(val,int):
return str(val)
cvt = f"{val:3.2e}"
if 'e' not in cvt:
return cvt
# a will be #.##
# b will be -##
a,b = cvt.split('e')
exp = int(b)
if exp % 3 == 0:
return cvt
if exp % 3 == 1:
a = a[0]+a[2]+a[1]+a[3]
exp = abs(exp-1)
return f"{a}e{b[0]}{exp:02d}"
a = a[0]+a[2]+a[3]+a[1]
exp = abs(exp-2)
return f"{a}e{b[0]}{exp:02d}"
for val in (5.34e-01, 2.95e+03, 5.34e-02, 2.95e+04, 5.34e-03, 2.95e+06):
print( f"{val:3.2e} ->", convert(val) )
Output:
5.34e-01 -> 534.e-03
2.95e+03 -> 2.95e+03
5.34e-02 -> 53.4e-03
2.95e+04 -> 29.5e+03
5.34e-03 -> 5.34e-03
2.95e+06 -> 2.95e+06
In this case, I think multiplying/dividing by 1000 is enough to move between SI prefixes. But when units get more complicated it might help to use a library like Pint to keep track of things and make sure you're calculating what you think you are.
In this case you might do:
import pint
ureg = pint.UnitRegistry()
Q = ureg.Quantity
reading_v = Q(5.34e-02, 'volts')
reading_mv = reading_v.to('millivolts')
print(reading_mv.magnitude)
but it seems overkill here.
Ive written this code and ive obtained the desired output however it is not in the correct format. Essentially the codewars challenge was to take a number of seconds up to around 350000 and then split it into hours then minutes then seconds. For example my code would take x seconds then express it as y:z:p (where y, z and p represent single digit integers) however i would like my code to express it as 0y:0z:0p unless y,z or p are already two digit integers.
Here is my code:
secs = 350000
mins = secs/60
hrs = mins/60
hrs_hol = int(hrs)
print(hrs_hol, hrs)
hrs_rem = hrs-hrs_hol
print(hrs_rem)
mins_from_hrs_rem = hrs_rem*60
mins_hol = int(mins_from_hrs_rem)
mins_rem = mins_from_hrs_rem - mins_hol
secs_from_min_rem = mins_rem*60
secs_final = int(secs_from_min_rem)
H = str(hrs_hol)
M = str(mins_hol)
S = str(secs_final)
print(H+':'+M+':'+S)
Thankyou!
Try this:
H = str(hrs_hol).zfill(2)
M = str(mins_hol).zfill(2)
S = str(secs_final).zfill(2)
Remove the assignments to H, M & S then:
print(f'{hrs_hol:02d}:{mins_hol:02d}:{secs_final:02d}')
Here we use an f-string and a format specifier that indicates a minimum of two digits (left-padded with zero if necessary)
I am asked to do this:
Write a program that adds one second to a clock time, given its hours, minutes and seconds.
Input consists of three natural numbers h, m and s that represent a clock time, that is, such that h<24, m<60 and s<60.
This is the code I came up with:
from easyinput import read
h = read(int)
m = read(int)
s = read(int)
seconds = (s+1)%60
minutes = (m + (s+1)//60)%60
hours = h + (m + (s+1)//60))//60
print(hours, minutes, seconds)
It does its function well, if I have
13 59 59
it returns
14 0 0
I am sure it could be bettered, but that's not the problem right now.
The problem is that I need the format to be like this:
11:33:16
It should be “HH:MM:SS”, and I don't know how to do it.
Anyone could help me?? Thanksss :)))
Use an f-string with format modifiers. 02d says "an int with field width 2 padded with 0."
print(f"{hours:02d}:{minutes:02d}:{seconds:02d}")
>>> hours = 13
>>> minutes = 3
>>> seconds = 5
>>> print(f"{hours:02d}:{minutes:02d}:{seconds:02d}")
13:03:05
>>>
Note that the d in the format specifiers is unnecessary. You could write:
print(f"{hours:02}:{minutes:02}:{seconds:02}")
Documentation on f-strings.
Usually, you don't want to deal with calculating date and time yourself, so a better approach is to use the native library that works with date and time out of the box:
from datetime import datetime, timedelta
from easyinput import read
h, m, s = read(int), read(int), read(int)
time = datetime.now().replace(hour=h, minute=m, second=s)
time += timedelta(seconds=1)
print(time.strftime("%H:%M:%S"))
print(f'{hours:>02}:{minutes:>02}:{seconds:>02}')
I have a CSV file having online Teams meeting data. It has two columns, one is "names" and the other with their duration of attendance during the meeting. I want to convert this information into a graph to quickly identify who remained for a long time in the meeting and who for less time. The duration column data is in this format, 3h 54m. This means it has the characters h and m in the column. See the picture below too.
Now how can I convert this data into decimal values like 3.54 or 234?
3.54 will mean hours and 234 will mean minutes in total. I am happy with any solution like either hour i.e. 3.54 or minutes 234.
Numpy or Pandas are both welcome.
The conversion of the timestring can be achieved with the datetime module:
from datetime import datetime
time_string = '3h 54m'
datetime_obj = datetime.strptime(time_string, '%Hh %Mm')
total_mins = (datetime_obj.hour * 60) + datetime_obj.minute
time_in_hours = total_mins / 60
# Outputs: `3.9 234`
print(time_in_hours, total_mins)
Here '%H' means the number of hours and '%M' is the number of minutes (both zero-padded). If this is encapsulated in a function, it can applied on the data from your spreadsheet that has been read-in via numpy or pandas.
REFERENCE:
https://docs.python.org/3/library/datetime.html#datetime.datetime.strptime
3h 54m is not 3.54. It's 3 + 54/60 = 3.9. Also since you have some items with seconds, it may be best to do all the conversions to seconds so you don't lose significant digits due to rounding if you need to add any of the items. For example, if you have 37 minutes, that's 0.61666667 hours. So using seconds, you get more precise results if you have to combine things.
The function below can handle h m and s and any combo of them. I provide examples at the bottom. I'm sure there are hundreds of ways to do this conversion. There are tons of examples on StackOverflow of reading and using CSV files so I didn't provide info. I like playing with the math stuff. :)
def hms_to_seconds(time_string):
timeparts = []
# split string. Assumes blank space(s) between each time componet
timeparts = time_string.split()
h = 0
m = 0
s = 0
# loop through the componets and get values
for part in timeparts:
if (part[-1] == "h"):
h = int( part.partition("h")[0] )
if (part[-1] == "m"):
m = int( part.partition("m")[0] )
if (part[-1] == "s"):
s = int( part.partition("s")[0] )
return (h*3600 + m*60 + s)
print(hms_to_seconds("3h 45m")) # 13500 sec
print(hms_to_seconds("1m 1s")) # 61 sec
print(hms_to_seconds("1h 1s")) # 3601 sec
print(hms_to_seconds("2h")) # 7200 sec
print(hms_to_seconds("10m")) # 600 sec
print(hms_to_seconds("33s")) # 33 sec
1. Read .csv
Reading the csv file into memory can be done using pd.read_csv()
2. Parse time string
Parser
Ideally you want to write a parser that can parse the time string for you. This can be done using ANTLR or by writing one yourself. See e.g. this blog post. This would be the most interesting solution and also the most challenging one. There might be a parser already out there which can handle this as the format is quite common, so you might wanna search for one.
RegEx
A quick and dirty solution however can be implemented using RegEx. The idea is to use this RegEx [0-9]*(?=h) for hours, [0-9]*(?=m) for minutes, [0-9]*(?=s) for seconds to extract the actual values before those identifiers and then calculate the total duration in seconds.
Please note: this is not an ideal solution and only works for "h", "m", "s" and there are edge cases that are not handled in this implementation but it does work in principle.
import re
duration_calcs = {
"h": 60 * 60, # convert hours to seconds => hours * 60 * 60
"m": 60, # convert minutes to seconds => minutes * 60
"s": 1, # convert seconds to seconds => seconds * 1
}
tests_cases = [
"3h 54m",
"4h 9m",
"12s",
"41m 1s"
]
tests_results = [
int(14040), # 3 * 60 * 60 + 54 * 60
14940, # 4 * 60 * 60 + 9 * 60
12, # 12 * 1
2461 # 41 * 60 + 1 * 1
]
def get_duration_component(identifier, text):
"""
Gets one component of the duration from the string and returns the duration in seconds.
:param identifier: either "h", "m" or "s"
:type identifier: str
:param text: text to extract the information from
:type text: str
:return duration in seconds
"""
# RegEx using positive lookahead to either "h", "m" or "s" to extract number before that identifier
regex = re.compile(f"[0-9]*(?={identifier})")
match = regex.search(text)
if not match:
return 0
return int(match.group()) * duration_calcs[identifier]
def get_duration(text):
"""
Get duration from text which contains duration like "4h 43m 12s".
Only "h", "m" and "s" supported.
:param text: text which contains a duration
:type text: str
:return: duration in seconds
"""
idents = ["h", "m", "s"]
total_duration = 0
for ident in idents:
total_duration += get_duration_component(ident, text)
return total_duration
def run_tests(tests, test_results):
"""
Run tests to verify that this quick and dirty implementation works at least for the given test cases.
:param tests: test cases to run
:type tests: list[str]
:param test_results: expected test results
:type test_results: list[int]
:return:
"""
for i, (test_inp, expected_output) in enumerate(zip(tests, test_results)):
result = get_duration(test_inp)
print(f"Test {i}: Input={test_inp}\tExpected Output={expected_output}\tResult: {result}", end="")
if result == expected_output:
print(f"\t[SUCCESS]")
else:
print(f"\t[FAILURE]")
run_tests(tests_cases, tests_results)
Expected result
Test 0: Input=3h 54m Expected Output=14040 Result: 14040 [SUCCESS]
Test 1: Input=4h 9m Expected Output=14940 Result: 14940 [SUCCESS]
Test 2: Input=12s Expected Output=12 Result: 12 [SUCCESS]
Test 3: Input=41m 1s Expected Output=2461 Result: 2461 [SUCCESS]
split()
Another (even simpler) solution could be to split() at space and use some if statements to determine whether a part is "h", "m" or "s" and then parse the preceding string to int and convert is as shown above. The idea is similar, so I did not write a program for this.
I have a program that is a converter for times in minutes and seconds and returns a float value with a decimal, for example:
6.57312
I would like to extract the .57312 part in order to convert it to seconds.
How can I get python to take only the value after the decimal point and put it into a variable that I can then use for the conversion?
You can do just a simple operation
dec = 6.57312 % 1
math.modf does that. It also has the advantage that you get the whole part in the same operation.
import math
f,i = math.modf(6.57312)
# f == .57312, i==6.0
Example program:
import math
def dec_to_ms(value):
frac,whole = math.modf(value)
return "%d:%02d"%(whole, frac*60)
print dec_to_ms(6.57312)
You can do this also
num = 6.57312
dec = num - int(num)