Simple datetime conversion from integer or string - python-3.x

Is there a simple way to convert a start and end time input into a list of evenly separated times? the input can be string or integer with format 1000,"1000",or "10:00" in 2400hr format. I've managed to accomplish this in a messy looking way, is there a tighter more efficient way to create this list? As you'll notice I created an array first and then called .tolist() to make the time transformation iteration easier. The problem is that an input of 1030 or 1015 would need to be translated into 1050 or 1025 to create the right spacing but if there were a way I could call a datetime.timedelta or something and cleanly make the array?
start="1000"
end="1600"
total_minutes=(int(end[:2])*60)+int(end[2:])-(int(start[:2])*60)-
int(start[2:])
dog=list(range(0,int(total_minutes),25))
walk=dog_df["Walk Length"][dog_df.index[dog_df["Name"]==self.name][0]]
if walk=='half':
self.dogarr=np.array([(x-25,x,x+25,x+50) for x in dog])
elif walk=='full':
self.dogarr=np.array([(x-25,x,x+25,x+50,x+75,x+100) for x in dog])
else:
self.dogarr=np.array([(x,x+25,x+50) for x in dog])
if int(start[2])!=0:
start=start[:2]+str(int(int(start[2:])*1.667))
self.dogarr+=(int(start))
self.dogarr=self.dogarr.tolist()
z=0
while z<len(self.dogarr):
for timespot in self.dogarr[z].copy():
self.dogarr[z][self.dogarr[z].index(timespot)]=time.strftime('%H%M', time.gmtime(self.dogarr[z][self.dogarr[z].index(timespot)]*36))
z+=1
self.dogarr=np.array(self.dogarr)```
array([['1115', '1130', '1145', '1200'],
['1130', '1145', '1200', '1215'],
['1145', '1200', '1215', '1230'],
['1200', '1215', '1230', '1245'],
['1215', '1230', '1245', '1300']], dtype='<U4')

I'm sure you can figure out to parse times from any number of existing questions. The crux of your question seems to be how to create evenly separated times within a range. Here's a simple way:
start = datetime.datetime(2018,12,20,10) # or use strptime etc.
end = datetime.datetime(2018,12,24,18)
count = 10
interval = (end - start) / count
dt = start
while dt <= end:
print(dt)
dt += interval
The output is:
2018-12-20 10:00:00
2018-12-20 20:24:00
2018-12-21 06:48:00
2018-12-21 17:12:00
2018-12-22 03:36:00
2018-12-22 14:00:00
2018-12-23 00:24:00
2018-12-23 10:48:00
2018-12-23 21:12:00
2018-12-24 07:36:00
2018-12-24 18:00:00

Related

Sorting dictionary by keys that are dates

When developing a telegram bot, you need to sort the dictionary by date, to output news in chronological order. The problem is the difference in key formats (dates). There is the format %d.%m at %H:M%, and there is %d.%m.%Y at %H:M%.
for k,v in sorted(Dnews_dict.items(), key=lambda x: DT.strptime(x[1].get("time"),'%d.%m.%Y at %H:%M')):
news = f"<b>{v['time']}</b>\n"\
f"{hlink(v['title'],v['url'])}"
await message.answer(news)
This code works fine, but only with 1 date type. As an option, i tried to add a string length condition (length is constant).
if len(round_data) == 18:
for k,v in sorted(Dnews_dict.items(), key=lambda x:DT.strptime(x[1].get("time"),'%d.%m.%Y в %H:%M')):
news = f"<b>{v['time']}</b>\n"\
f"{hlink(v['title'],v['url'])}"
await message.answer(news)
else:
for k,v in sorted(Dnews_dict.items(), key=lambda x:DT.strptime(x[1].get("time"),'%d.%m at %H:%M')):
news = f"<b>{v['time']}</b>\n"\
f"{hlink(v['title'],v['url'])}"
await message.answer(news)
But the condition doesn’t work. But that condition doesn’t work. How can this dilemma be resolved?
enter image description here
While I am unfamiliar with the telegraph bot, the following is a way to deal with datetime data having mixed formats e you have isolated the specific text containing the date time data:
So given a list of mixed datetime string data of the following formats:
datelist = ['08.02.2022 at 23:53',
'13.07 at 18:13',
'23.11.2022 at 19:55',
'15.02 at 01:06',
'09.07.2022 at 14:57',
'09.08 at 04:06',
'19.04.2022 at 07:19',
'28.10 at 21:56',
'19.10.2022 at 02:18',
'23.04 at 18:15']
from dateutil import parser #Utility for handling all the messy dates you encounter along the way
from dateutil.relativedelta import *
for dt in datelist:
print(parser.parse(dt))
Yields:
2022-08-02 23:53:00
2023-01-13 18:13:00
2022-11-23 19:55:00
2023-01-15 01:06:00
2022-09-07 14:57:00
2023-01-09 04:06:00
2022-04-19 07:19:00
2023-01-28 21:56:00
2022-10-19 02:18:00
2023-01-23 18:15:00
If the year 2023 is of concern, you can do the following:
for dt in datelist:
dtx = parser.parse(dt)
if dtx.year == 2023:
dtx = dtx + relativedelta(year=2022)
print(dtx)
Which produces a result keyed to the year 2022:
2022-08-02 23:53:00
2022-01-13 18:13:00
2022-11-23 19:55:00
2022-01-15 01:06:00
2022-09-07 14:57:00
2022-01-09 04:06:00
2022-04-19 07:19:00
2022-01-28 21:56:00
2022-10-19 02:18:00
2022-01-23 18:15:00

Time Duration in python

Given two strings :
ex:
start_time="3:00 PM"
Duration="3:10"
Start time is in 12-hour clock format (ending in AM or PM), and duration time
that indicates the number of hours and minutes
Assume that the start times are valid times.The minutes in the duration time will
be a whole number less than 60, but the hour can be any whole number.
I need to add the duration time to the start time and return the result
(WITHOUT ANY USE OF LIBRARIES).
The result should be in 12-hour clock format (ending in AM or PM) indicates the
number of hours and minutes
ex:
start_time = "6:30 PM"
Duration = "205:12"
# Returns: 7:42 AM
I Tried and finally got the required answer but unable to produce correct AM or PM for
the result after addition.
what I Tried:
start_time = "6:30 PM"
Duration = "205:12"
#My answer =7:42
#expected :7:42 AM
Can someone help me with the logic to produce correct AM or PM after addition of start
time and Duration.
def add_time(a,b):
a=a.split()
b=b.split()
be=int(a[0][:a[0].find(':')])
af=int(a[0][a[0].find(':')+1:])
be1 = int(b[0][:b[0].find(':')])
af1 = int(b[0][b[0].find(':') + 1:])
return(((be+be1)//24)+1)
s=be+(be1)%12
p=af+af1
if ((s>12) and (p<60)) :
return(str(s-12)+":"+str(p))
elif ((s<12) and (p>60)) :
f = p-60
if len(str(f))<=1:
return(str(s+1)+":"+str('0'+str(f)))
else:
return (str(s + 1)+":"+(str(f)))
elif ((s<12) and (p<60)) :
return(str(s)+":"+str(p))
elif ((s>12) and (p>60)):
f=p-60
if len(str(f)) <= 1:
return (str((s -12)+1)+":"+('0' + str(f)))
else:
return (str((s -12)+1)+":"+(str(f)))
print(add_time("10:10 PM", "3:30"))
# Returns: 1:40 AM
print(add_time("11:43 PM", "24:20"))
# Returns: 12:03 AM
Your code does not seem to cover all edge cases, e.g. add_time("11:43 PM", "1:20") returns None because the case s==12 is not covered.
Therefore one should put <= instead of < in the respective if conditions. The case where the addition of the minutes leads to hours greater than 12 although the addition of the hours itself did not, is not covered either. So we should check the minutes first and the hours after that instead of simultaneously.
To make the code more readable, we use f-strings and can use str.split() with an argument, forgive me for changing the code quite a bit:
def add_time(a,b):
start = a.split()
start_h, start_m = [int(val) for val in start[0].split(':')]
start_app = start[1]
dur_h, dur_m = [int(val) for val in b.split(':')]
end_m = start_m+dur_m
end_h = end_m//60
end_m %= 60
end_h += start_h+dur_h
if (end_h//12)%2==0:
end_app = start_app
else:
end_app = 'AM' if start_app=='PM' else 'PM'
return f'{end_h:02}:{end_m:02} {end_app}'

Average time without changing format using pandas

Below is my avg_df:
Date Model INumber Type TimeDiff Device
326 20/07/18 TG I625 Devicetime 0:02:31 RD
328 20/07/18 TG I5271 Devicetime 0:00:32 RD
332 20/07/18 TG I660 Devicetime 0:00:31 RD
I want to get average of "TimeDiff". I know that i can convert Time into secs and get avg and can format it back, but would be interested to know if there is any way that i can get without formatting time back and forth. something like below:
print(avg_df.loc[:,"TimeDiff"].mean())
Appreciate any help!
You can get the average if you convert it to timedelta first:
>>> pd.to_timedelta(df['TimeDiff']).mean()
Timedelta('0 days 00:01:11.333333')

svm train output file has less lines than that of the input file

I am currently building a binary classification model and have created an input file for svm-train (svm_input.txt). This input file has 453 lines, 4 No. features and 2 No. classes [0,1].
i.e
0 1:15.0 2:40.0 3:30.0 4:15.0
1 1:22.73 2:40.91 3:36.36 4:0.0
1 1:31.82 2:27.27 3:22.73 4:18.18
0 1:22.73 2:13.64 3:36.36 4:27.27
1 1:30.43 2:39.13 3:13.04 4:17.39 ......................
My problem is that when I count the number of lines in the output model generated by svm-train (svm_train_model.txt), this has 12 fewer lines than that of the input file. The line count here shows 450, although there are obviously also 9 lines at the beginning showing the various parameters generated
i.e.
svm_type c_svc
kernel_type rbf
gamma 1
nr_class 2
total_sv 441
rho -0.156449
label 0 1
nr_sv 228 213
SV
Therefore 12 lines in total from the original input of 453 have gone. I am new to svm and was hoping that someone could shed some light on why this might have happened?
Thanks in advance
Updated.........
I now believe that in generating the model, it has removed lines whereby the labels and all the parameters are exactly the same.
To explain............... My input is a set of miRNAs which have been classified as 1 and 0 depending on their involvement in a particular process or not (i.e 1=Yes & 0=No). The input file looks something like.......
0 1:22 2:30 3:14 4:16
1 1:26 2:15 3:17 4:25
0 1:22 2:30 3:14 4:16
Whereby, lines one and three are exactly the same and as a result will be removed from the output model. My question is then both why the output model would do this and how I can get around this (whilst using the same features)?
Whilst both SOME OF the labels and their corresponding feature values are identical within the input file, these are still different miRNAs.
NOTE: The Input file does not have a feature for miRNA name (and this would clearly show the differences in each line) however, in terms of the features used (i.e Nucleotide Percentage Content), some of the miRNAs do have exactly the same percentage content of A,U,G & C and as a result are viewed as duplicates and then removed from the output model as it obviously views them as duplicates even though they are not (hence there are less lines in the output model).
the format of the input file is:
Where:
Column 0 - label (i.e 1 or 0): 1=Yes & 0=No
Column 1 - Feature 1 = Percentage Content "A"
Column 2 - Feature 2 = Percentage Content "U"
Column 3 - Feature 3 = Percentage Content "G"
Column 4 - Feature 4 = Percentage Content "C"
The input file actually looks something like (See the very first two lines below), as they appear identical, however each line represents a different miRNA):
1 1:23 2:36 3:23 4:18
1 1:23 2:36 3:23 4:18
0 1:36 2:32 3:5 4:27
1 1:14 2:41 3:36 4:9
1 1:18 2:50 3:18 4:14
0 1:36 2:23 3:23 4:18
0 1:15 2:40 3:30 4:15
In terms of software, I am using libsvm-3.22 and python 2.7.5
Align your input file properly, is my first observation. The code for libsvm doesnt look for exactly 4 features. I identifies by the string literals you have provided separating the features from the labels. I suggest manually converting your input file to create the desired input argument.
Try the following code in python to run
Requirements - h5py, if your input is from matlab. (.mat file)
pip install h5py
import h5py
f = h5py.File('traininglabel.mat', 'r')# give label.mat file for training
variables = f.items()
labels = []
c = []
import numpy as np
for var in variables:
data = var[1]
lables = (data.value[0])
trainlabels= []
for i in lables:
trainlabels.append(str(i))
finaltrain = []
trainlabels = np.array(trainlabels)
for i in range(0,len(trainlabels)):
if trainlabels[i] == '0.0':
trainlabels[i] = '0'
if trainlabels[i] == '1.0':
trainlabels[i] = '1'
print trainlabels[i]
f = h5py.File('training_features.mat', 'r') #give features here
variables = f.items()
lables = []
file = open('traindata.txt', 'w+')
for var in variables:
data = var[1]
lables = data.value
for i in range(0,1000): #no of training samples in file features.mat
file.write(str(trainlabels[i]))
file.write(' ')
for j in range(0,49):
file.write(str(lables[j][i]))
file.write(' ')
file.write('\n')

Remove certain dates in list. Python 3.4

I have a list that has several days in it. Each day have several timestamps. What I want to do is to make a new list that only takes the start time and the end time in the list for each date.
I also want to delete the Character between the date and the time on each one, the char is always the same type of letter.
the time stamps can vary in how many they are on each date.
Since I'm new to python it would be preferred to use a lot of simple to understand codes. I've been using a lot of regex so pleas if there is a way with this one.
the list has been sorted with the command list.sort() so it's in the correct order.
code used to extract the information was the following.
file1 = open("test.txt", "r")
for f in file1:
list1 += re.findall('20\d\d-\d\d-\d\dA\d\d\:\d\d', f)
listX = (len(list1))
list2 = list1[0:listX - 2]
list2.sort()
here is a list of how it looks:
2015-12-28A09:30
2015-12-28A09:30
2015-12-28A09:35
2015-12-28A09:35
2015-12-28A12:00
2015-12-28A12:00
2015-12-28A12:15
2015-12-28A12:15
2015-12-28A14:30
2015-12-28A14:30
2015-12-28A15:15
2015-12-28A15:15
2015-12-28A16:45
2015-12-28A16:45
2015-12-28A17:00
2015-12-28A17:00
2015-12-28A18:15
2015-12-28A18:15
2015-12-29A08:30
2015-12-29A08:30
2015-12-29A08:35
2015-12-29A08:35
2015-12-29A10:45
2015-12-29A10:45
2015-12-29A11:00
2015-12-29A11:00
2015-12-29A13:15
2015-12-29A13:15
2015-12-29A14:00
2015-12-29A14:00
2015-12-29A15:30
2015-12-29A15:30
2015-12-29A15:45
2015-12-29A15:45
2015-12-29A17:15
2015-12-29A17:15
2015-12-30A08:30
2015-12-30A08:30
2015-12-30A08:35
2015-12-30A08:35
2015-12-30A10:45
2015-12-30A10:45
2015-12-30A11:00
2015-12-30A11:00
2015-12-30A13:00
2015-12-30A13:00
2015-12-30A13:45
2015-12-30A13:45
2015-12-30A15:15
2015-12-30A15:15
2015-12-30A15:30
2015-12-30A15:30
2015-12-30A17:15
2015-12-30A17:15
And this is how I want it to look like:
2015-12-28 09:30
2015-12-28 18:15
2015-12-29 08:30
2015-12-29 17:15
2015-12-30 08:30
2015-12-30 17:15
First of all, you should convert all your strings into proper dates, Python can work with. That way, you have a lot more control on it, also to change the formatting later. So let’s parse your dates using datetime.strptime in list2:
from datetime import datetime
dates = [datetime.strptime(item, '%Y-%m-%dA%H:%M') for item in list2]
This creates a new list dates that contains all your dates from list2 but as parsed datetime object.
Now, since you want to get the first and the last date of each day, we somehow have to group your dates by the date component. There are various ways to do that. I’ll be using itertools.groupby for it, with a key function that just looks at the date component of each entry:
from itertools import groupby
for day, times in groupby(dates, lambda x: x.date()):
first, *mid, last = times
print(first)
print(last)
If we run this, we already get your output (without date formatting):
2015-12-28 09:30:00
2015-12-28 18:15:00
2015-12-29 08:30:00
2015-12-29 17:15:00
2015-12-30 08:30:00
2015-12-30 17:15:00
Of course, you can also collect that first and last date in a list first to process the dates later:
filteredDates = []
for day, times in groupby(dates, lambda x: x.date()):
first, *mid, last = times
filteredDates.append(first)
filteredDates.append(last)
And you can also output your dates with a different format using datetime.strftime:
for date in filteredDates:
print(date.strftime('%Y-%m-%d %H:%M'))
That would give us the following output:
2015-12-28 09:30
2015-12-28 18:15
2015-12-29 08:30
2015-12-29 17:15
2015-12-30 08:30
2015-12-30 17:15
If you don’t want to go the route through parsing those dates, of course you could also do this simply by working on the strings. Since they are nicely formatted (i.e. they can be easily compared), you can do that as well. It would look like this then:
for day, times in groupby(list2, lambda x: x[:10]):
first, *mid, last = times
print(first)
print(last)
Producing the following output:
2015-12-28A09:30
2015-12-28A18:15
2015-12-29A08:30
2015-12-29A17:15
2015-12-30A08:30
2015-12-30A17:15
Because your data is ordered you just need to pull the first and last value from each group, you can use re.sub to remove the single letter replacing it with a space then split each date string just comparing the dates:
from re import sub
def grp(l):
it = iter(l)
prev = start = next(it).replace("A"," ")
for dte in it:
dte = dte.replace("A"," ")
# if we have a new date, yield that start and end
if dte.split(None, 1)[0] != prev.split(None,1)[0]:
yield start
yield prev
start = dte
prev = dte
yield start, prev
l=["2015-12-28A09:30", "2015-12-28A09:30", .....................
l[:] = grp(l)
This could also certainly be done as your process the file without sorting by using a dict to group:
from re import findall
from collections import OrderedDict
with open("dates.txt") as f:
od = defaultdict(lambda: {"min": "null", "max": ""})
for line in f:
for dte in findall('20\d\d-\d\d-\d\dA\d\d\:\d\d', line):
dte, tme = dte.split("A")
_dte = "{} {}".format(dte, tme)
if od[dte]["min"] > _dte:
od[dte]["min"] = _dte
if od[dte]["max"] < _dte:
od[dte]["max"] = _dt
print(list(od.values()))
Which will give you the start and end time for each date.
[{'min': '2016-01-03 23:59', 'max': '2016-01-03 23:59'},
{'min': '2015-12-28 00:00', 'max': '2015-12-28 18:15'},
{'min': '2015-12-30 08:30', 'max': '2015-12-30 17:15'},
{'min': '2015-12-29 08:30', 'max': '2015-12-29 17:15'},
{'min': '2015-12-15 08:41', 'max': '2015-12-15 08:41'}]
The start for 2015-12-28 is also 00:00 not 9:30.
if you dates are actually as posted one per line you don't need a regex either:
from collections import defaultdict
with open("dates.txt") as f:
od = defaultdict(lambda: {"min": "null", "max": ""})
for line in f:
dte, tme = line.rstrip().split("A")
_dte = "{} {}".format(dte, tme)
if od[dte]["min"] > _dte:
od[dte]["min"] = _dte
if od[dte]["max"] < _dte:
od[dte]["max"] = _dte
print(list(od.values()
Which would give you the same output.

Resources