Convert a time string into a decimal number of hours? [duplicate] - python

This question already has answers here:
Time to decimal time in Python
(3 answers)
Closed 9 years ago.
How can I convert a string like "12:30" or "5:51:23" into a decimal number representing the amount of elapsed hours in Python?

Fairly simple string-splitting and math:
def time_string_to_decimals(time_string):
fields = time_string.split(":")
hours = fields[0] if len(fields) > 0 else 0.0
minutes = fields[1] if len(fields) > 1 else 0.0
seconds = fields[2] if len(fields) > 2 else 0.0
return float(hours) + (float(minutes) / 60.0) + (float(seconds) / pow(60.0, 2)
If only a single number is given like "3", this will return 3.0. If two colon-delimited values are given like "4:57", this will return 4.95. If three colon-delimited values are given like "14:36:27", this will return 14.6075.

Possible Solution
>>> time_st = ["12:30" , "5:51:23"]
>>> HMS = [60*60, 60, 1]
>>> for t in time_st:
dec_time = sum(a * b for a,b in zip(HMS, map(int, t.split(":"))))
dec_time /= 3600.
print "{} = {}".format(t, dec_time)
12:30 = 12.5
5:51:23 = 5.85638888889
00:00 = 0.0
23:59 = 23.9833333333

>>> float('5:51:23'.split(':')[0])
5.0

Related

Returning multiple values from function in python 3.5 [duplicate]

This question already has answers here:
How can I return two values from a function in Python?
(8 answers)
Closed 6 years ago.
I'm trying to get some help in returning values from "year_calc" function below (Python 3.5). In essence, the code works for returning "b" as I need a new starting value for "b" to be passed to "year_calc" for each iteration - I can get that to work just fine. However, I want the "total_cost" value from each year_calc iteration to be returned and added up until finished. Note the "grand_total" under the while loop. I realize this doesn't work as stated - just adding it so it may add clarity to what I'm attempting to accomplish. I am just not sure how to pull a specific value which is being returned. Any insight?
def main():
archive_total = float(input('Enter archive total (GB): '))
transfer_rate = float(input('Enter transfer rate (Gbps): '))
days_to_transfer = ((((archive_total*8/transfer_rate)/60)/60)/24)
xfer_per_day = archive_total/days_to_transfer
day_cost = xfer_per_day * 0.007 / 30
days = 365
total_days = 0
sum = 0
b = xfer_per_day * 0.007 / 30
total_years = 1
grand_total = 0.0
total_cost = 0.0
while total_years < years_to_transfer + 1:
b = year_calc(day_cost, days, total_days, sum,b,total_years,total_cost)
total_years += 1
grand_total += total_cost
def year_calc(day_cost,days,total_days,sum,b,total_years,total_cost):
while total_days < days -1:
b += day_cost
sum += b
total_days += 1
total_cost = sum + day_cost
print('Year',total_years,'cost: $', format(sum + day_cost, ',.2f'))
return (b, total_cost)
main()
year_calc, as with any function that returns multiple items, will return its values in a tuple. Therefore, you can just change this line:
b = year_calc(day_cost, days, total_days, sum,b,total_years,total_cost)
to this one:
b, total_cost = year_calc(day_cost, days, total_days, sum,b,total_years)
This works because of how Python handles multiple assignment:
>> a, b = 1,2
>> print a
1
>> print b
2
As an aside, you should try to avoid using builtin names like sum for your variables. And I'm not sure what years_to_transfer is - do you define that elsewhere in your code?
If I understand correctly your description correctly, this implements what you want:
def main():
# ...
total_cost = 0.0
while total_years < years_to_transfer + 1:
b, total_cost = year_calc(day_cost, days, total_days, sum,b,total_years,total_cost)
# ...
def year_calc(day_cost,days,total_days,sum,b,total_years,total_cost):
# ...
return (b, total_cost)
main()
Hmm, seems a bit like trying to code VBA in Python... :-)
Ok, first: I don't think you want to pass total_cost to the function year_calc, as you do not depend on any value you get. So remove it from the definition line:
def year_calc(day_cost,days,total_days,sum,b,total_years):
...
Next: you calculate a new value for total_cost and return a tupple from the function. That's pretty correct.
Now, when callin year_calc you should remove the total_cost variable from calling the function. But you should remember that you return a tupple, so assign the value to a tupple:
(b, total_cost) = year_calc(day_cost, days, total_days, sum,b,total_years)
Bottom line: there are no ref variables (or output variables, ...) to be sent in a function in python. Put in the parameters, nothing more. If you want to return 2 different calculations, return a tupple, but assign the value also to a tupple. Much cleaner.

How to do a loop that takes into account each day of a specific month?

got a weird one i can not figure out how to solve
basically i have to run a section of code, this code extracts data from a file, which name is the format year-month-day-hour-00-00-consensus
so what i am trying to do is complete a loop that after the code runs adds an hour then once it gets to midnight adds a day etc, however while i have this working, i can not figure out how i can do this for the months as if it was easy as all months being 30 days for example this would be simple, i am having issues defining the length of days in the month, does any one have any ideas ?
this is the code so far :
def calculate_and_write_hsdir(h,d,m,y):
if h < 24:
if d < 10:
d = "0"+str(d)
if h < 10:
h = "0"+str(h)
if m < 10:
m = "0"+str(m)
consensus_file_name = str(y) + "-" + str(m) + "-" + str(d) + "-" + str(h) + "-00-00-consensus"
print consensus_file_name
..... do stuff ....
h = int(h) + 1
else:
h = 00
d = int(d) + 1
# d = d + 1
i pre set this by :
h = 00 #Hour
d = 01 #Day
m = 10 #Month
y = 2013 #Year
calculate_and_write_hsdir(h,d,m,y)
# def run_calculate(h,d,m,y):
# if m == 02:
# if d == 28:
# calculate_and_write_hsdir(h,d,m,y)
i want to start at 2013-10-01 and end at the present day, how can i achieve this ? sorry if it is a bit confusing but struggle on explaining what i want it to achieve
Python has a datetime module that will handle this for you. You make a datetime object representing the date and time, and a timedelta object to represent the addition of 1 hour. You can then, if you need to, check whether the new date is within the same day as the original date by comparing the .day property of the datetime object.
datetime also has a convenient method strftime for printing formatted output based on the date and time.
from datetime import datetime, timedelta
def calculate_and_write_hsdir(h,d,m,y):
before = datetime(hour = h, day = d, month = m, year = y)
now = before + timedelta(hours = 1)
if before.day == now.day:
print 'still the same day'
# ... do stuff ...
else:
print "now it's a different day"
# ... do other stuff ...
print now.strftime('%Y-%m-%d-%H-00-00-consensus')
h = 00 #Hour
d = 01 #Day
m = 10 #Month
y = 2013 #Year
calculate_and_write_hsdir(h, d, m, y)

While Loop to produce Mathematical Sequences?

I've been asked to do the following:
Using a while loop, you will write a program which will produce the following mathematical sequence:
1 * 9 + 2 = 11(you will compute this number)
12 * 9 + 3 = 111
123 * 9 + 4 = 1111
Then your program should run as far as the results contain only "1"s. You can build your numbers as string, then convert to ints before calculation. Then you can convert the result back to a string to see if it contains all "1"s.
Sample Output:
1 * 9 + 2 = 11
12 * 9 + 3 = 111
123 * 9 + 4 = 1111
1234 * 9 + 5 = 11111
Here is my code:
def main():
Current = 1
Next = 2
Addition = 2
output = funcCalculation(Current, Addition)
while (verifyAllOnes(output) == True):
print(output)
#string concat to get new current number
Current = int(str(Current) + str(Next))
Addition += 1
Next += 1
output = funcCalculation(Current, Next)
def funcCalculation(a,b):
return (a * 9 + b)
def verifyAllOnes(val):
Num_str = str(val)
for ch in Num_str:
if(str(ch)!= "1"):
return False
return True
main()
The bug is that the formula isn't printing next to the series of ones on each line. What am I doing wrong?
Pseudo-code:
a = 1
b = 2
result = a * 9 + b
while string representation of result contains only 1s:
a = concat a with the old value of b, as a number
b = b + 1
result = a * 9 + b
This can be literally converted into Python code.
Testing all ones
Well, for starters, here is one easy way to check that the value is all ones:
def only_ones(n):
n_str = str(n)
return set(n_str) == set(['1'])
You could do something more "mathy", but I'm not sure that it would be any faster. It would much more easily
generalize to other bases (than 10) if that's something you were interested in though
def only_ones(n):
return (n % 10 == 1) and (n == 1 or only_ones2(n / 10))
Uncertainty about how to generate the specific recurrence relation...
As for actually solving the problem though, it's actually not clear what the sequence should be.
What comes next?
123456
1234567
12345678
123456789
?
Is it 1234567890? Or 12345678910? Or 1234567900?
Without answering this, it's not possible to solve the problem in any general way (unless in fact the 111..s
terminate before you get to this issue).
I'm going to go with the most mathematically appealing assumption, which is that the value in question is the
sum of all the 11111... values before it (note that 12 = 11 + 1, 123 = 111 + 11 + 1, 1234 = 1111 + 111 + 11 + 1, etc...).
A solution
In this case, you could do something along these lines:
def sequence_gen():
a = 1
b = 1
i = 2
while only_ones(b):
yield b
b = a*9 + i
a += b
i += 1
Notice that I've put this in a generator in order to make it easier to only grab as many results from this
sequence as you actually want. It's entirely possible that this is an infinite sequence, so actually running
the while code by itself might take a while ;-)
s = sequence_gen()
s.next() #=> 1
s.next() #=> 11
A generator gives you a lot of flexibility for things like this. For instance, you could grab the first 10 values of the sequence using the itertools.islice
function:
import itertools as it
s = sequence_gen()
xs = [x for x in it.islice(s, 10)]
print xs

Holiday program error in Python

I was asked to make a program that takes the day that I start my travel length of my stay as an input and give the day that I return in as an output so I tried this and I keep getting an error that says (KeyError = -3)
Note: I'm a beginner, so be easy on me :)
dect = {0:'Sunday', 1: 'Monday', 2:'Tuesday',3:'Wednesday', 4:'Thursday',
5:'Friday',6:'Saturday'
}
def day(x):
print( dect[x])
def holiday(start,length):
length = length + start
while True:
if length <= 0:
break
print(length)
else:
length = length - 7
day(length)
s = int(input('Enter the start day: '))
l = int(input('Enter the length of your stay: '))
holiday(s,l)
The value of length can become negative and this is why you're looking up -3 in the dictionary.
For example, if my holiday is 4 days (length = 4) then you're doing length = length - 7 which means you're calling day() with -3 as value.
Your dictionary only has values for the keys 0 - 6 and that's why you're getting a KeyError as the key -3 is not in the dictionary.
You can fix it by changing the check into if length < 7.
What you can do is, simply use datetime module.
from datetime import date,timedelta
d = date.today() + timedelta(days=2)
print d
You can use timedelta to add as many days/hours/whatever you want. See here for the documentation.
Replace your holiday function as -
def holiday(start,length):
length = length + start
length = length % 7
day(length)

Long Count Mayan Date in Python

I need to compile a program that can convert a Gregorian date to a Mayan one. I also need to use 01/01/1970 as a reference date.
The following auxiliary functions work accordingly and have no mistakes.
# turns dates into tuples
def dmj(date):
"""
>>> dmj('01/01/1970')
(1, 1, 1970)
>>> dmj('00012+00012+02012')
(12, 12, 2012)
"""
tup = ()
for i in date:
if i.isdigit() == False and i != ' ':
date = date.replace(i, ' ')
number_str = ''
for i in date:
number_str += i
if i == ' ':
number = int(number_str)
tup += (number,)
number_str = ''
tup += (int(number_str),)
return tup
# counts days that have passed since 01/01/1970
def daysPassed(date):
"""
>>> daysPassed('01/01/1970')
0
>>> daysPassed('20-7-1988')
6775
>>> daysPassed('00012+00012+02012')
15686
"""
from datetime import date
tup = dmj(date)
begin = date(1970, 1, 1)
end = date(tup[2], tup[1], tup[0])
passed = abs(end - begin)
return passed.days
My idea was to first calculate how many days have passed since the beginning of this pictun (20 baktuns long) in 01/01/1970 and then added the days passed since then according to the given date.
In the Mayan calendar a day is refered to as a kin. Their periods (within one pictun) are as follows:
20 kin = 1 uinal; 18 uinal = 1 tun; 20 tun = 1 katun; 20 katun = 1 baktun
In the long count notation the Mayan date for 01/01/1970 is '12.17.16.7.5'. Baktun are written first, then katuns, etc... Mayan dates start from 0. Basically the first kin of a uinal is number zero and the last one number 19, twenty in total.
I've first compiled the following:
def mayanDate(date, separation='')
"""
>>> mayanDate('01/01/1970')
'12/17/16/7/5'
>>> mayaDate('20-7-1988', separator='/')
'12/18/15/4/0'
>>> mayaDate('00012+00012+02012', separator='-')
'12-19-19-17-11'
>>> mayaDate('21 12 2012', separator='+')
'13+0+0+0+0'
>>> mayaDate('26.03.2407')
'14.0.0.0.0'
"""
days = daysPassed(date) + 13 * 144000 + 18 * 7200\
+ 17 * 400 + 8 * 20 + 6
baktun = str((days //((20 **3) * 18)) - 1)
days = days % ((20 **3) * 18)
katun = str((days //((20 **2) * 18)) - 1)
days = days % ((20 **2) * 18)
tun = str((days // (20 **2)) - 1)
days = days % (20 **2)
uinal = str((days // 20) - 1)
days = days % 20 - 1
kin = str(days)
mayanlist = [baktun, katun, tun, uinal, kin]
for i in date:
if i.isdigit() == False and separator == '':
separator = i
break
mayandate = separator.join(mayanlist)
return mayandate
For some strange reason only 01/01/1970 returns the correct Mayan long notation, despite counting from the beginning of an entire pictun (7,900 years in length!). For all other dates it seems to advance too fast through the calendar, despite my second auxiliary function returning the correct values (even for millennia into the future).
I wonder where's the mistake. For instance mayanDate('20-7-1988') returns '12-18-15-6-0' instead of '12-18-15-4-0' and mayanDate('21 12 2012') returns '13 0 1 12 0' instead of '13 0 0 0 0'.
The issue you're seeing with the negative 1 kin for date '15/01/1970' is due to the removal of one from every date ordinal during the calculation. Taking x%20 will always return a value between 0 and 19 inclusive. Taking one from the result necessarily shifts this range to -1 to 18 inclusive.
The number added to the result of daysPassed(date) seems to be a conversion of the long form of 1/1/1970, with one added to each digit. I'm assuming this has been done to counter the fact that the Mayan calendar starts counting at zero, but is unnecessary. The Mayan date 0.0.0.0.1.5 counts 25, not 151646. This doesn't appear to be the source of the error though, since removing this issue from my own code, I still get the same results as described for the 20-7-1988 and 21-12-2012.
I finally rooted out the error when I went back and switched out all the magic numbers in my code for named constants (it makes the code far easier to debug, read and maintain). You state there are 18 uinal in a tun, and 20 tun in a katun, but these numbers are reversed in the code.
Here's my code:
def mayanDate(date_str, seperation=','):
days_in_kin = 1
kin_in_uinal = 20
uinal_in_tun = 18
tun_in_katun = 20
katun_in_baktun = 20
days_in_uinal = days_in_kin * kin_in_uinal
days_in_tun = days_in_uinal * uinal_in_tun
days_in_katun = days_in_tun * tun_in_katun
days_in_baktun = days_in_katun * katun_in_baktun
days_1970 = 12 * days_in_baktun \
+ 17 * days_in_katun\
+ 16 * days_in_tun\
+ 7 * days_in_uinal\
+ 5 * days_in_kin
total_days = daysPassed(date_str) + days_1970
baktun = total_days // days_in_baktun
total_days -= baktun * days_in_baktun
katun = total_days // days_in_katun
total_days -= katun * days_in_katun
tun = total_days // days_in_tun
total_days -= tun * days_in_tun
uinal = total_days // days_in_uinal
total_days -= uinal * days_in_uinal
kin = total_days // days_in_kin
print seperation.join(map(str, (baktun, katun, tun, uinal, kin)))
(I subtracted the previous calculations from total days, rather than using a modulo operator, since I feel it's cleaner. I guess it's a matter of personal preference.)
I may have found something.
>>>mayanDate('15/01/1970')
'12/17/16/8/-1'
Obviously not possible. -1 has to be 19 here and 8 has to be 7. It seems to turn month too early. Still not out why 01/01/1970 remains correct here. No idea what's so special about that date.

Categories