Outils pour utilisateurs

Outils du site


issue164:python

Ceci est une ancienne révision du document !


Last month, we looked at using the datetime library to, among other things, calculate a billing cost for hours worked. Unfortunately, I didn’t have enough time or space to discuss adding multiple hours worked to get a “grand total” to bill the customer. One would assume that since you can subtract two datetime objects, that you could add two datetime objects just as easily. But you can’t. If we use an example from last month and have the two datetime objects st and et (meaning start time and end time), and try to add them – which really makes no sense, but let’s try it anyway – you will receive the text shown below.

While there are a few ways to actually add times using datediff, they are very clumsy, and I really don’t think I could properly explain it, so I started looking for a better solution. After digging around on the Internet, I found this discussion on stackoverflow.com. (https://stackoverflow.com/questions/2410454/adding-up-time-durations-in-python). Banderlog013 answered the question the best, so I grabbed a copy of his code. It seems the solution is “simply” to use the numpy library. After playing around with the code, I realized that, for my needs, it didn’t quite give me what I needed. Here (top right) is his original code, including his comments.

While this worked on a basic level, it wasn’t really what I wanted. So I started modifying the code. But, before we get too deep into the code, I will remind you that you need to have the numpy library installed. Most of my regular readers already have done this, but let’s go through the motions – just in case you haven’t done this yet. You can simply use pip (or pip3) to install numpy … $ pip3 install numpy If numpy is already installed, that’s ok. You’ll just get a gentle message that you have already done this … Requirement already satisfied: numpy in ./.local/lib/python3.8/site-packages (1.19.2)

The program assumes that you have the hours put into a text file. Here ‘s the one that I will use for this project. It’s simply just a series of task times for our mythical employee. One entry per line. 06:00:00 03:00:00 02:08:00 03:10:00 11:10:00 08:00:00 Make sure that you press <Enter> after you make the last entry in the text file. You can use any text editor you wish, from Vim, to nano, or your favorite IDE. Save the file as “hours-11-20-20.txt” .

Now that is taken care of, let’s look at the code (after I modified it), block by block, with some explanations along the way. To run the program, you will need to use a version of Python that is 3.7 or later, since I use “f-strings” throughout. First, we need to import numpy into our program, and then read the file. The data from the file is going to be put into a variable named “x”. At this point, most of this this is the code from Banderlog013, including his original comments (top right). At this point, the data that is in the variable “tmp” is: ['06:00:00', '03:00:00', '02:08:00', '03:10:00', '11:10:00', '08:00:00', ] I didn’t include microseconds in my data entries, so it’s just a list of the simple strings that we had entered into the file. Also notice that the last element of the list is a blank string, which is why he mentions that he needed to drop the last item in his comments. Now, we need to take each entry in our list and convert that into a list of lists. # get list of ['00', 02, '12.31'] tmp = [i.split(“:”) for i in tmp.copy()] print(f“tmp={tmp}”) The print statement is mine – so that we can see the data. The variable tmp now contains: tmp='06', '00', '00'], ['03', '00', '00'], ['02', '08', '00'], ['03', '10', '00'], ['11', '10', '00'], ['08', '00', '00'], ['' There is the list of lists I mentioned above. Next, we create an empty list that will hold each of the items and then walk through each item, convert that to a numpy float array, append that to the empty list (np_tims) see below. So this is the end of the for loop. At this point, the program has printed each of the values for np_tmp and has appended each into the np_tims list. Our output, at this time, looks like this: np_tmp=[6. 0. 0.] np_tmp=[3. 0. 0.] np_tmp=[2. 8. 0.] np_tmp=[ 3. 10. 0.] np_tmp=[11. 10. 0.] np_tmp=[8. 0. 0.] And the np_tims list looks like this: [array([6., 0., 0.]), array([3., 0., 0.]), array([2., 8., 0.]), array([ 3., 10., 0.]), array([11., 10., 0.]), array([8., 0., 0.])] We are getting close to the “magic” of what the program does. Since we are done with the for loop, we’ll now use the .sum function of numpy. He originally divided the array sums by another array of [24, 60, 1000]. However when that happened, it threw the numbers off. So I changed the code to leave the array sums as it was, which worked for me. # X = np.array(np_tims).sum(axis=0) / np.array([24, 60, 1000]) X = np.array(np_tims).sum(axis=0) # / np.array([1, 60, 1000]) print(X) Now when we hit the print(X) line, the output from our program presents us with: [33. 28. 0.] At this point, we pull the hour and minute values from the list so that we can easily deal with them. hrs = X[0] mins = X[1] print(hrs, mins) And the output here would be: 33.0 28.0 And, as you know, the value on the left is hours with the value on the right being the minutes. Notice that I don’t really care about seconds at this point, so they are ignored. Next, we convert the hours to seconds by multiplying by 3600, and the minutes by 60, and then adding them together. totalsecs = (hrs * 3600) + (mins * 60) print(f“TotalSecs: {totalsecs}”) TotalSecs: 120480.0 You COULD make the line: Totalsecs = (X[0] * 3600) + (X[1] * 60) Which is much more intuitive and requires a lot less programming, but I wanted to break it down into easily “digestible chunks”. As we did last month, we use divmod to convert the numbers into hours, minutes and seconds just in case we have more minutes than 60 so the values correlate correctly: min, sec = divmod(totalsecs, 60) hours, minutes = divmod(min, 60) print(f“{hours} hours and {minutes} minutes”) 33.0 hours and 28.0 minutes Luckily, in this example the numbers match. Finally, we apply our billing factor. In this case, our mythical programmer bills out at $25 per hour, AND we bill portions of an hour instead of rounding everything up to the next hour. billingratehours = 25 billingrateminutes = 25 / 60 billtotal = (hours * billingratehours) + (minutes * billingrateminutes) print(f“Bill= ${billtotal:.2f}”) Bill= $836.67 If you look at the print statement at the end of the code block, we format the total amount to be billed to only two decimal points by using the “:.2f” constructor. What if we didn’t format the billtotal variable? The program would print: Bill= $836.6666666666666 Which doesn’t make sense for a billing amount. Since we spent time creating a program, I thought long and hard about how to provide the source code. If I went to pastebin as I have in the past, you would have to make two separate downloads, but if I put the code on my github repository, then you have to download only one happy little zip file. So, I have put the code in my github repository. You can download them at https://github.com/gregwa1953/FCM164. As always, until next time; stay safe, healthy, positive and creative!**

issue164/python.1609177716.txt.gz · Dernière modification : 2020/12/28 18:48 de d52fr