Python - Calculate the difference between two datetime.time objects - python-3.x

I have two datetime.time objects and I want to calculate the difference in hours between them. For example
a = datetime.time(22,00,00)
b = datetime.time(18,00,00)
I would like to be able to subtract these so that it gives me the value 4.

To calculate the difference, you have to convert the datetime.time object to a datetime.datetime object. Then when you subtract, you get a timedelta object. In order to find out how many hours the timedelta object is, you have to find the total seconds and divide it by 3600.
# Create datetime objects for each time (a and b)
dateTimeA = datetime.datetime.combine(datetime.date.today(), a)
dateTimeB = datetime.datetime.combine(datetime.date.today(), b)
# Get the difference between datetimes (as timedelta)
dateTimeDifference = dateTimeA - dateTimeB
# Divide difference in seconds by number of seconds in hour (3600)
dateTimeDifferenceInHours = dateTimeDifference.total_seconds() / 3600

This is how I did
a = '2200'
b = '1800'
time1 = datetime.strptime(a,"%H%M") # convert string to time
time2 = datetime.strptime(b,"%H%M")
diff = time1 -time2
diff.total_seconds()/3600 # seconds to hour
output: 4.0

I got my result from this problem:
a='2017-10-10 21:25:13'
b='2017-10-02 10:56:33'
a=pd.to_datetime(a)
b=pd.to_datetime(b)
c.total_seconds()/3600
but in series that wont work:
table1['new2']=table1['new'].total_seconds()/3600

Aside, but this might bother more users finding this question...
To calculate the difference between pandas columns, better is not to have time as type datetime.time in the first place, but as numpy.timedelta64 instead (duration since midnight). One way to fix this:
from datetime import datetime, date, time
for c in df.select_dtypes('object'):
if isinstance(df[c][0], time):
df[c] = df[c].apply(lambda t: datetime.combine(date.min, t) - datetime.min)

Related

How to convert a continuous numbered array into a timestamp

I am gathering data on a device, and after every second, I update a count and log it. I am now processing it, and am new to python, so I had a question as to whether it was possible to convert a numbered array [0,1,2,3,4,...1091,1092,1093,...] into a timestamp [00:00:01, 00:00:02, 00:00:03, 00:00:04, ... 00:18:11, 00:18:12, 00:18:13,...] for example.
If you could please lead me in the right direction, that would be very much appreciated!
p.s. In the future, I will be logging the data as a timestamp, but for now, I have 5 hours' worth of data that needs to be processed!
import datetime as dt
timestamp=[0,1,2,3,4,5,1092,1093]
print([dt.timedelta(seconds=ts) for ts in timestamp])
Happy Coding
If all you have is seconds, then you can just do simple arithmetic to convert them to minutes and hours:
inp = [0, 1, 2, 3, 4, 1091, 1092, 1093]
outp = [f'{secs // 3600:02}:{(secs // 60) % 60:02}:{secs % 60:02}' for secs in inp]
print(outp)
# ['00:00:00', '00:00:01', '00:00:02', '00:00:03', '00:00:04', '00:18:11', '00:18:12', '00:18:13']
Here, I use a list comprehension and, for each secs in the input, create a format string:
hours is secs // 3600 (that's integer floor division), because one hour is 3600 seconds
Minutes is (secs // 60) % 60 (this incorporates the modulo operator, which displays the remainder of secs // 60 after dividing it by 60 again). One minute is 60 seconds, but more than 60 minutes would be an hour, so we need to make sure to 'roll over' the counter every 60 minutes (which is what the mod is for).
Seconds is, of course, secs % 60, because a minute has 60 seconds and we want the counter to roll over.
The format string starts with f', and anything inside {} is an instruction to evaluate whatever's inside it, and insert that into the string. The syntax is {expression:format}, where display is an optional instruction for how to format the data (i.e. not just printing it out). And format can get complicated (look up a python f-string tutorial if you're curious about the specifics), but suffice it to say that in this case we use 02, which means that we want the output to be two characters in length, and padded with zeroes in case it's less than that.

Is there a way i can use datetime to convert a string to milliseconds without using timedelta?

I'm trying to convert a string containing a time ("%H:%M:%S.%f") to an int of the equivalent milliseconds. The complication is, the time is the output from FFmpeg, it's a point in the audio file. I need to get the number of milliseconds the time in the string represents. The timestamp method in DateTime is milliseconds from epoche, without another time stamp from when I began, this is no good.
For example:
t = "00:05:52.654321"
should be converted to:
i = 352654321
What is the best way to accomplish this?
This is how I figured out to do it.
def _convert_string_to_int(self, s) -> int:
begin = datetime.datetime(1900,1,1)
end = datetime.datetime.strptime(s, self._ffmpeg_format_string)
return int((end - begin).total_seconds() * 1000000)
It just feels really unnecessary to use timedelta like that.
Since timestamps are relative to the Unix Epoch (1970-01-01) you can make a datetime object from your time by prepending that date to it and then getting the timestamp of the resultant object to get the time string converted to seconds . Since python timestamps are floating point representations of seconds since the epoch, you will need to multiply by 1000 and convert to integer to get the number of milliseconds:
from datetime import datetime
t = "00:05:52.654321"
d = datetime.strptime('1970-01-01 ' + t, '%Y-%m-%d %H:%M:%S.%f')
print(int(d.timestamp()*1000))
Output:
352654
If you actually want microseconds, multiply by 1000000 instead.
As an alternative, you can split the time string on : and sum the parts, multiplying by 60 or 3600 to convert the hour and minute parts to seconds:
t = "00:05:52.654321"
millisecs = int(sum([float(v) * 1000 * 60 ** (2 - i) for i, v in enumerate(t.split(':'))]))
print(millisecs)
Output:
352654
Again, if you want microseconds, just multiply by 1000000 instead of 1000.
A number of milliseconds is inherently a time interval, so there is good reason why datetime.timedelta instances have a total_seconds method while datetime.datetime, datetime.date and datetime.time do not have one.
In principle you could use datetime.datetime.time(end) to get an object with properties including hour, minute, second and microsecond, and then use these to construct an arithmetic expression for the elapsed time since midnight on the same day. However, the supported way to handle time intervals like this is precisely the timedelta approach that you are already using.

Converting UNIX time from Nanoseconds to Seconds

I am reading in time stamps as strings from a service that is UNIX time formatted in Nano seconds. This introduces an obvious problem in that I can't conduct standard operations to normalize the strings to seconds given how large they are. An example of one of these strings is '1589212802642680000' or 1.58921E+18 in scientific notation.
I was trying something like this: convert_fills_df['timeStamp'] = convert_fills_df.timeStamp.apply(lambda x: UNIX_EPOCH + (float(x)/1000000000)). But I overflow the float object when I try this; is there a string operation I can do without losing precision down to the second? Nanoseconds for my purpose are not necessary (though I appreciate their thoroughness). If I could keep the nanoseconds that's great too, but it is not a necessity.
I would like to just convert the time to a human readable format in 24 hour clock format.
The first 10 digits represents the seconds, the subsequent digits represent milli, micro & nanosecond precision
To keep all the information you can insert . at the right position, and pass the string to pd.to_datetime
df = pd.DataFrame({'ns': ['1589212802642680000']})
pd.to_datetime(df.ns.str[:10] + '.' + df.ns.str[10:], unit='s')
# outputs
0 2020-05-11 16:00:02.642679930
Name: ns, dtype: datetime64[ns]

How do I round an input variable to a certain number

I am using python 3+ and I want to round a variable up to 500 and if the input is higher than 500 then it rounds up to 1000. Is there a way I could math.ceil() or round() ?
I have done this so far but I'm not sure whether I have come across it in the right way.
import math
x = int(input("how much data did you use this month? "))
math.ceil(x / 500.0) * 500.0
print(x)
I want to round x up to 500 whatever the number is but if it is higher (e.g - 600) I want it to round it to 1000. The last line does not work and only prints what the user inputted.
math.ceil() returns the value that you expect but you haven't assignet it to anything.
Simply assign that value to your variable.
This is the solution:
import math
x = int(input("how much data did you use this month? "))
x = math.ceil(x / 500.0) * 500.0
print(x)
Have you tried:
x = math.ceil(x / 500.0) * 500.0
to update your x variable before printing your x variable?

Return value from DataFrame at maximum of a function

For narrow banded processing I want the complex pressure at the peak frequency bin. To find the peak frequency bin I use the frequency with the highest absolute value, within a small range of frequencies.
I have come up with the following code, borrowing heavily from
Use idxmax for indexing in pandas
This seems to me bulky, and hard to generalize. Ideally I hope to be able to be able to make fBins into an array, and return many frequencies at once. Its OK to make maxAbsIndex into a list, but I can't see the next step.
import numpy as np
import pandas as pd
# Construct fake frequency data on multiple channels
np.random.seed(0)
numF = 1000
f = np.arange(numF) / (numF * 2)
y = np.random.randn(numF, 2) + 1j * np.random.randn(numF, 2)
# Put time series into a DataFrame, indexed by frequency
yFrame = pd.DataFrame(y, index = f)
fBins = 0.1
tol = 0.01
# Find the index of the maxium absolute value within a given frequency window
absMaxIndex = yFrame[(fBins - tol) : (fBins + tol)].abs().idxmax()
# Return the value at this index
value = [yFrame.ix[items[1], items[0]] for items in absMaxIndex.iteritems()]
print(value)
Value should have the complex value
[(-2.0946030712061448-1.0585718976053677j), (-2.7396771671895563+0.79204149842297422j)]
Which have the largest absolute value in yFrame between 0.09 and 0.11 Hz for each channel.

Resources