How to get a period of time with Numpy? - python

If a np.datetime64 type data is given, how to get a period of time around the time?
For example, if np.datetime64('2020-04-01T21:32') is given to a function, I want the function to return np.datetime64('2020-04-01T21:30') and np.datetime64('2020-04-01T21:39') - 10 minutes around the given time.
Is there any way to do this with numpy?

Numpy does not have a built in time period like Pandas does.
If all you want are two time stamps the following function should work.
def ten_minutes_around(t):
t = ((t.astype('<M8[m]') # Truncate time to integer minute representation
.astype('int') # Convert to integer representation
// 10) * 10 # Remove any sub 10 minute minutes
).astype('<M8[m]') # convert back to minute timestamp
return np.array([t, t + np.timedelta64(10, 'm')]).T
For example:
for t in [np.datetime64('2020-04-01T21:32'), np.datetime64('2052-02-03T13:56:03.172')]:
s, e = ten_minutes_around(t)
print(s, t, e)
gives:
2020-04-01T21:30 2020-04-01T21:32 2020-04-01T21:40
2652-02-03T13:50 2652-02-03T13:56:03.172 2652-02-03T14:00
and
ten_minutes_around(np.array([
np.datetime64('2020-04-01T21:32'),
np.datetime64('2652-02-03T13:56:03.172'),
np.datetime64('1970-04-01'),
]))
gives
array([['2020-04-01T21:30', '2020-04-01T21:40'],
['2652-02-03T13:50', '2652-02-03T14:00'],
['1970-04-01T00:00', '1970-04-01T00:10']], dtype='datetime64[m]')

To do so we can get the minute from the given time and subtract it from the given time to get the starting of the period and add 9 minutes to get the ending time of the period.
import numpy as np
time = '2020-04-01T21:32'
dt = np.datetime64(time)
base = (dt.tolist().time().minute) % 10 // base would be 3 in this case
start = dt - np.timedelta64(base,'m')
end = start + np.timedelta64(9,'m')
print(start,end,sep='\n')
I hope this helps.

Related

Dealing with time format greater than 24 hours

I have data of experiments with time greater than 24 hours. For ex. [23:24:44, 25:10:44]. To operate duration of tests, I like to use Python, however I have a value error when I create datetime.time() with hours more than 23:59:.
You could split your time by the colons in order to get a list of the component parts, which you could then use to initialise your timedelta:
from datetime import timedelta
myDuration = "25:43:12"
mD = [int(x) for x in myDuration.split(":")]
delta = timedelta(hours=mD[0], minutes=mD[1], seconds=mD[2])
print(delta)
# 1 day, 1:43:12

How do I convert integer into a time format

How would I go about converting a float like 3.65 into 4 mins 5 seconds.
I have tried using:
print(datetime.datetime.strptime('3.35','%M%-S'))
However, I get this back:
ValueError: '-' is a bad directive in format '%-M:%-S'
Take a look at the following script, you can figure out how to make it work for days years, etc, this only works if we assume the format is "hours.minutes"
import datetime
# Assuming the 3 represents the hours and the 0.65 the minutes
number = 3.65
# First, we need to split the numbero into its whole decimal part
# and its decimal part
whole_decimal_part = hours = int(number) # 3
decimal_part = number % whole_decimal_part # 0.6499999
# Now, we need to know how many extra hours are in the decimal part
extra_hours = round((decimal_part * 100) / 60) # 1
minutes = round((decimal_part * 100) % 60) # 5
hours += extra_hours # 4
time_str = "%(hours)s:%(minutes)s" % {
"hours": hours,
"minutes": minutes
} # 4:5
final_time = datetime.datetime.strptime(time_str, "%H:%M").time()
print(final_time) # 04:05:00
First, you should complain to whoever is giving you time data expressed like that.
If you need to process minutes and seconds as a standalone value, then the datetime object may not your best choice either.
If you still need to convert "3.65" into a datetime object corresponding to "4-05" you could adjust it to be a valid time representation before passing it to strptime()
m,s = map(int,"3.65".split("."))
m,s = (m+s)//60,s%60
dt = datetime.datetime.strptime(f"{m}-{s}","%M%-S")
Split your time into minute and seconds
If seconds is 60 or more, then add extra minutes (//) ; second is the modulo (%)
t="3.65"
m, s = [int(i) for i in t.split('.')]
if s >= 60:
m += s//60
s = s % 60
print(f'{m} mins {s} seconds') # -> 4 mins 5 seconds
while 65 seconds cannot be parsed correctly so you have to manipulate by yourself to clean the data first before parsing.
NOTE: assuming seconds is not a very very big number which can make minutes>60
import datetime
time= '3.65'
split_time = time.split(".")
minute =int(split_time[0])
seconds = int(split_time[1])
minute_offset, seconds = divmod(seconds, 60);
minute = int(split_time[0]) + minute_offset
print(datetime.datetime.strptime('{}.{}'.format(minute,seconds),'%M.%S')) #1900-01-01 00:04:05
You can alternatively use .time() on datetime object to extract the time
print(datetime.datetime.strptime('{}.{}'.format(minute,seconds),'%M.%S').time()) #00:04:05
A much cleaner and safer solution is (to consider hour as well). Convert everything into seconds and then convert back to hours, minutes, seconds
def convert(seconds):
min, sec = divmod(seconds, 60)
hour, min = divmod(min, 60)
return "%d:%02d:%02d" % (hour, min, sec)
time='59.65'
split_time = time.split(".")
minute =int(split_time[0])
seconds = int(split_time[1])
new_seconds = minute*60 +65
datetime.datetime.strptime(convert(new_seconds),'%H:%M:%S').time()

How do I turn a number into a date?

I have a dataset with the dates given in numbers from 1995 to 2016.
1/1/1995 is equal to 1, 2/1/1995 is 2 and 31/12/2016 is 8036, so every day is one number.
How do I turn my time array [1,2,3,...,8034,8035,8036] into dates of dd/mm/yyyy?
Use the datetime.fromordinal(x) method. This creates a date from the number x, signifying the number of days since 0001-01-01.
If you want to start with x==1 being 1995-01-01, you can do
d = datetime.date(1,1,1) # actual date does not matter
print d.fromordinal( datetime.date(1994,12,31).toordinal() + x)
where x is the number of days since the last day of 1994.
Use the epoch conversion which is also supported by the python time library. The unix epoch time starts on 01/01/1970 and is counted in seconds. If you add 788932800 seconds to reach 01/01/1995, you can then add 86400 (seconds per day) and can use standard techniques to calculated the "seconds from epoch" back to a correct date.
Example code:
#!/usr/bin/python
import time
entryid = 5
epochdate = 788932800 + entryid * 86400
print time.strftime("%d/%m/%y", time.gmtime(epochdate))
does this help for first 100 days? You can change the no though.
import time
epochOne = 788918400 #epoch for 1995-01-01 00:00:00
oneDay = 86400 #epoch for 86400
noOfDays = 8036
for each in range(noOfDays):
epochEach = epochOne + (each * oneDay)
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(epochEach)))

string conversion to hours and minutes (not pandas standard time)

Lets say for e.g., I have (series) data in string format (e.g., '225586:47'). I want the machine to understand that this denotes hours and minutes.
Any idea how achieve this?
import pandas as pd
#this function will split a string, and treat each part as a part of a time
#then return seconds as an integer
def get_secs(time_str): #assumes string is in format HH:MM
h, m = time_str.split(':')
return int(h) * 3600 + int(m) * 60 #convert everything into seconds
#This function will take seconds and convert into a string
#in the format of "HH:MM"
#Note that if there are fractions of a minute, these will be rounded down to make MM an integer
def get_hhmm(secs):
hours = secs / (3600) #get the hours from seconds
minutes = (hours - int(hours)) * (60) # remainder as minutes
return "%02i:%02i" % (hours, minutes) #we have to integer-ize both of these since they are each floats
#dummy series
s = pd.Series(['10:20', '20:30', '30:40', '40:50', '50:60'])
#apply this function to the elements of your series
s = s.apply(get_secs)
#sum them
sum(s) #as seconds
sum(s)/60 #as minutes
sum(s)/60/60 #as hours
print(get_hhmm(sum(s))) #as an "hh:mm" string
I split the string based on the ":", took the first part, converted it to integer and multiplied it by 60. Took the second part, converted it to integer and added to the product that I got from the first part.
Did this for the entire column, added the values, divided by 60 to get hours and minutes.

A way to convert numbers to seconds

I know this is not the best way to explain what I want to achieve, but I will try to do it by defining my desired output.
The context: An object passes Point A at 6:58 (format is: minute:second) and passes Point B at 7:12. Calculate the time taken to get from Point A to B.
Logically, you'd take B time away from A time to get your result. I expected:
0.14 because it takes the object 14 seconds but got 0.54 because Python by default won't know that I need it to calculate in seconds format, where the 59 is maximum before you reach a new leading number.
My code is as simple as:
A=6.58
B=7.12
print(B-A)
Solution 1 : if you do not absolutely need float as inputs
from datetime import datetime, date, time
a = datetime.combine(date.today(), time(0, 6, 58))
b = datetime.combine(date.today(), time(0, 7, 12))
Solution 2 : if your inputs are floats
from datetime import datetime, date, time
def float_to_datetime(myfloat):
minutes, seconds = str(myfloat).split('.')
return datetime.combine(date.today(), time(0, int(minutes), int(seconds)))
a = float_to_datetime(6.58)
b = float_to_datetime(7.12)
In both cases, the output is:
print(b - a)
0:00:14
print((b-a).total_seconds())
14.0

Categories