Python timedelta receiving unexpected results - python

In a web application I'm writing for an existing database I need to calculate the difference between now and a timestamp stored in the database (in a text field, it's stupid, I know). Here's my sqlalchemy Ban class and the relevant method.
class Ban(base):
__tablename__= 'bans'
id= Column('banID', Integer, primary_key=True)
unban_timestamp= Column('UNBAN', Text)
banned_steamid= Column('ID', Text, ForeignKey('rp_users.steamid'))
banned_name= Column('NAME', Text)
banner_steamid= Column('BANNER_STEAMID', Text, ForeignKey('rp_users.steamid'))
banner_name= Column('BANNER', Text)
reason= Column('REASON', Text)
def unbanned_in(self, mode):
if self.unban_timestamp == '0':
return 'Never'
else:
now= datetime.datetime.utcnow()
time= datetime.datetime.fromtimestamp(int(self.unban_timestamp))
if now > time:
return 'Expired'
else:
remaining= time - now
if mode=='readable':
return remaining
elif mode=='int':
return str(remaining.seconds).zfill(10)
I need both the integer and the pretty string representations because I'll be presenting this in a html table and javascript needs a simple way to sort it. The problem I'm facing is that the integers and strings are not matching up, as you can see in this screenshot here:
if anyone can make sense of why the output is so screwed up that would be appreciated! if there's any more information that you need to answer my question I'll gladly add it.
edit
for the record at the top of the screenshot the unbanned_in timestamp is 1320247970 if I run that through my function this is the result I get
>>> ban = session.query(db.Ban).filter_by(id=3783).one()
>>> print ban.unbanned_in('int'), ban.unbanned_in('readable')
0000049044 2 days, 13:37:24.179045

If you want to get the number of seconds between time and now, use
remaining.days * 24 * 3600 + remaining.seconds
instead of just remaining.seconds

The output is screwed up because your calculation to convert a number of seconds to days, hours, minutes and seconds is wrong. Since you didn't post that bit of code that's all I can say, but note that there are 86400 seconds in a day and all of the counts of seconds you output are smaller than this.
The values you output for hours, minutes and seconds look fine, just your calculation for days is wrong.

Related

Calculating time in MM:SS:TSHSTS

So I'm working with time to format seconds to the format MM:SS:TSHSTS, meaning minutes:seconds:1/10 second 1/100 second 1/1000 second. This is basicly to calculate lap times for a racing simulator.
My input comes in seconds so for instance 124.6073 seconds -> 02:04:607.
I've produced this function and it works, I just want to know how can I optimize this since in my head this is kinda hammered as I couldn't think of something better at the time.
def convert_lap_times(seconds_per_lap):
minutes = seconds_per_lap // 60
seconds = seconds_per_lap % 60
rest = seconds_per_lap % 1
rest_str = str(rest).split('0.')
decimal_rest = rest_str[1]
return "%02i:%02i.%0.3s" % (minutes, seconds, decimal_rest)
So the rest is the decimal part of said number and all worked fine until that point. The "big" issue becomes when I want to get rid of the integer part, for instance 0.607, I just wanted 607 so I parsed it as a string... is there a better way?
Thanks a lot and all the best!
You could do it like this:
def convert_lap_times(seconds_per_lap):
return "{:02.0f}:{:06.3f}".format(*divmod(seconds_per_lap,60))
print(convert_lap_times(124.6073)) # 02:04.607

add hours to time string to match time zone in python

I have a string that looks like this
time = "2020-04-15 21:27"
That's based on normal time zone +0
how can i add hours to the string so it become like this
for example let's add 5 hours to the time
the time string will become like this
time = "2020-04-15 02:27"
then the day should be updated
so the final result will look like this
time = "2020-04-15 02:27"
how can i do that ?
Edit:
i also need to change the day because 24 hours have passed
It is unclear if you mean creating your own clock or just updating a string every hour.
Option one:
import time
While True:
t = time.ctime(%h)
print(t)
#the above produces a live clock only showing hours.
#you could add %s for seconds separated by commas and thd like.
Option 2:
import time
T = #whatever you want it to be
time.sleep(300)
T = the prev num bit you want to change + 5
Hope this helps!
Happy coding

How to convert time written "h.mm" to decimal form with Python?

I prompt the user to input what time they start and finish their job. Then I need to calculate what they will earn (given a 97 currency/hour salary). The answer should also not have any decimals (so it should be rounded off). I can't seem to get it to work though.
As shown below, I tried taking the difference between the two inputs from the user and then splitting them to hours and minutes. After that just doing the calculations.
difference = round(float(finishing_time)-float(start_time), 2)
hours, minutes = str(difference).split(".")
salary_hours = int(hours)*97
salary_minutes = int(minutes)//60*97
salary = salary_hours + salary_minutes
So if start_time = 8.30 and finishing_time = 11.15 the salary should be 267, but I get 291 currency.
A couple of things to be careful of, is the rounding off that occurs at every level, which also occurs when you do math by hand and pencil! There is a reason why when you perform calculations one typically does the rounding off when the entire calculation has been performed otherwise one would come up with a vastly different answer as you pointed out.
I'd tackle this perhaps by doing something like this
from datetime import datetime
# quick way to generate a datetime object with start time would be like
start_time = datetime.now()
# replace the hours and minutes you want in your case its
start_time = start_time.replace(hour=8, minute=30)
end_time = start_time.replace(hour=11, minute=15)
# calling replace returns a new distinct datetime object
def calculate_salary(start_time, finish_time, pay_rate):
# will be in seconds
delta_seconds = finish_time - start_time
# convert to hours
hours_worked = (delta_seconds.seconds) / 3600
# calculate pay
pay = hours_worked * pay_rate
return pay
In this case calling the function gives a value of
In [1]: calculate_salary(start_time, end_time, 97)
Out[1]: 266.75
While i dont advocate doing calculations on time without a time module. I assume you know what your doing and that your calculations are simple I.E they wont rolle over midnight and the finish time will always be greater than the start time and finish on the same day. With that in mind the following code should produce your result without using a datetime module. However like #william bright answer, a datetime module would be my prefernce for code like this.
def get_hours(time_string):
time_split = time_string.split(".")
whole_hours = int(time_split[0])
fraction_hours = int(time_split[1]) / 60
return whole_hours + fraction_hours
start_time=input("start time: ")
finish_time=input("finish_time: ")
total_hours = get_hours(finish_time)-get_hours(start_time)
salary = total_hours*97
print(round(salary))
OUTPUT
start time: 8.30
finish_time: 11.15
267
So, my bad for perhaps being unclear in my statement, but since this is a work in progress for the next couple weeks/months, what I came up with was the following:
starting_time = input("At what time did you start working? ")
finishing_time = input("At what time did you finish working? ")
hours1, minutes1 = starting_time.split(".")
hours2, minutes2 = finishing_time.split(".")
minutes1 = float(minutes1)/60
starting_time_new = float(hours1)+minutes1
minutes2 = float(minutes2)/60
finishing_time_new = float(hours2)+minutes2
salary = round((finishing_time_new-starting_time_new)*97)
print("Started working at:",b)
print("Stopped working at:",s)
print("Your salary is",salary,"currency.")
The solution from where I started was to just focus on changing the minutes to the correct decimals instead of focusing on the hours too.
I am well aware that it is far from perfect, in fact, it is probably really bad. However, I am new to programming in Python and taking a course to be better.

how to compare date (in query criteria) in pyral

I have a requirement to find the tasks which are not updated.
The criteria looks like :
'iteration.Name = \"iterationName\" and State!=Completed and LastUpdateDate<'+str(datetime.datetime.now())+"'"
This would result in:
iteration.Name = "iterationName" and State!=Completed and LastUpdateDate<'2015-12-27 20:17:08.769000'
I didn't get any results.
The rally task object has the LastUpdateDate as 2015-12-16T09:54:30.600Z 8.0
How do I compare the LastUpdateDate in the query criterion?
I had the same problem with multiple arguments in the end I had to add brackets to get it to work.
(('iteration.Name = \"iterationName\") AND (State!=Completed)) AND (LastUpdateDate<'+str(datetime.datetime.now())+"'")
There's probably too many brackets in there, the key thing I think was to get a bracket around the first two conditions; if adding another condition it would look something like this
((((condition1) AND (condition2)) AND (condition3)) AND (condition4))
Question was asked ages ago, but might be useful for people looking for using queries with dates in pyral.
There are several issues with the code in the question:
datetime.datetime.now() will probably not return a date in the format needed by Rally, so it is better to use strftime to get the proper format
Multiple conditions need to have correct set of parentheses; for example: ((((condition1) AND (condition2)) AND (condition3)) AND (condition4))
LastUpdateDate will necessarily be previous to current date (unless the users have been able to jump to the future).
It is better to put dates with double quotes (") instead of single quotes (')
Here is the code I came for identifying tasks that have not been updated in the last 5 days and are not completed.
iter_name = "2018-Iteration-4"
five_days_ago = datetime.datetime.now() - datetime.timedelta(days=5)
str_date = five_days_ago.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
tasks_not_updated = rally.get(
'Task',
query = '(((iteration.Name = "%s")'
' and (State != Completed))'
' and (LastUpdateDate < "%s"))' % (iter_name, str_date)
)
for task in tasks_not_updated:
print("%s (%s)" % (task.Name, task.State))

Time intervals as strings python

Im pretty new at programming and right now I'm working with Zoo in python, a programme where the user can put in a time interval by choice during the opening hours of the zoo. The Zoo is open from 07-23, and for example the bear is available from 08-18 to look at.
for example.
What time do you wish to visit the Zoo?
input by user: 10-13
At this time you can see the animals:
...
...
And the programme will write out exactly what animals are available for show at that time interval. Given our example, the bear will be available and be printed out.
Im wondering how I can easy make the programme translate the input by the user to a string or maybe with range, so I dont have to create a hundred different varibles like 06-06, 06-07, 06-08, 06-09 etc.
Any ideas?
Thanks!
I'd solve this by changing the ask a little bit to the following:
What time will you arrive at the Zoo? 9 am on 11/11/2015
How long would you like to stay? 3 hrs
This will let you use a nice date picker widget on the front end which you can then create a datetime object for the start. Next, create a timedelta object for the duration. You can apply the delta the the start object to get the end time so you don't have to worry about parsing.
The other reason I recommend this is anecdotally I've seen evidence that users perceive start and duration and more clear/easier to use rather than picking two times. Per the above, you plan on spending 4 hours at the Zoo, not being there specifically from X to Y, so this UI better matches the mental model.
You can store each interval as a pair of integers corresponding to the start/end of the time interval:
from collections import namedtuple
Interval = namedtuple('Interval', 'start end')
If you have a string such as '10-13'; you could convert it to Interval:
user_hours = Interval(*map(int, '10-13'.split('-')))
# -> Interval(start=10, end=13)
To find out "what animals are available for show at that time interval", you need to know whether two given time intervals intersect:
def intersect(a, b):
return a.start < b.end and b.start < a.end
Example:
>>> intersect(Interval(8,18), Interval(10,13))
True
There are no overnight intervals and therefore you could treat the time intervals as linear (intervals on a line).
Now, you only need to populate the table with visiting hours for zoo animals:
visiting_hours = {
"bear": Interval(8, 18), # 08-18
"lion": Interval(14, 16), # 14-16
}
and you can print which animals are available for the given user hours:
for animal, available_hours in visiting_hours:
if intersect(user_hours, available_hours):
print(animal)
As an alternative you could use datetime.time() instead of int to represent hours -- it enforces valid values (0..23) for hours automatically:
from datetime import datetime
while True:
user_input = input("Input time interval e.g., 10-13: ")
try:
user_hours = Interval(*[datetime.strptime(h, "%H").time()
for h in user_input.split('-')])
except ValueError as e:
print("Invalid input: %s. Try again." % (e,))
else:
break
Modify the "visiting hours" table accordingly:
from datetime import time
visiting_hours = {
"bear": Interval(time(8), time(18)),
"lion": Interval(time(14), time(16)),
}
You could automate the input e.g., by reading the visiting hours from a file.
The rest of the code stays the same.
You could save the visiting hours into a separate file e.g., SQLite database and edit the table independently (using another script):
#!/usr/bin/env python
import sqlite3
db = sqlite3.connect(':memory:') # create in memory for debugging
db.execute('''CREATE TABLE intervals
(animal text, start integer, end integer)''')
# populate
visiting_hours = [('bear', '08-18'), ('lion', '14-16')]
db.executemany('INSERT INTO intervals VALUES (?, ?, ?)',
[[animal] + list(map(int, hours.split('-')))
for animal, hours in visiting_hours])
To get the animals from the database:
# "what animals are available for show at that time interval"
for animal, in db.execute('''SELECT animal FROM intervals
WHERE ? < end and start < ?''',
tuple(map(int, '10-13'.split('-')))):
print(animal)

Categories