convert times like these 1h30m/13h30m/1d5m into seconds - python-3.x

time_convert = {"s":1, "m":60, "h":3600,"d":86400}
converted = int(time[0]) * time_convert[time[-1]]
That code above only converts the first first number to the corresponding converted time so 12h would come back as 3600 instead of 43200, so that way no other times would work for what I'm trying to do.
I'm wanting to convert any time the user says into seconds so, 1h5m,15h40m,1d55m ect

A regex based approach could work well:
total = 0
time_convert = {"s": 1, "m": 60, "h": 3600, "d": 86400}
for quantity, unit in re.findall("(\d+)([dhm])", "1h30m"):
total += time_convert[unit] * int(quantity)
print(total)
>>> 5400
re.findall returns all matches in a given string. We're matching for a number that's 1 or more digits long (\d+), then we're matching for one of d, h, or m. These first and second groups correspond to the quantity and the unit.

You can use also strptime to convert the string to a time object and timedelta to calculate the total number of seconds:
import time
from datetime import timedelta
time_str = "1h30m"
time_obj = time.strptime(time_str, "%Hh%Mm")
seconds = timedelta(hours=time_obj.tm_hour, minutes=time_obj.tm_min).total_seconds()
print(seconds)
This will output:
5400.0
You can find more on how to configure expected time format and others here: strptime and timedelta

Related

Python code to convert ffmpeg time duration value to seconds

I am seeking python 3.x code that can take a user-provided value in ffmpeg's time duration format and provide a float for the number of seconds represented by that duration. It would parse both formats described in the documentation and handle the s/ms/us prefix for the second format. The only thing I would not need is the optional negative. I mostly need this so I can provide the correct 'start_time' (seconds) for the fade and afade filters.
Please note, I am not asking how to get the duration of an input file. These are string values provided by the user.
I came up with the following code. It's not perfect, as it would probably accept some strings that ffmpeg would not, but it should be close enough for my immediate needs.
def duration_to_seconds(duration):
"""
Converts an ffmpeg duration string into a decimal representing the number of seconds
represented by the duration string; None if the string is not parsable.
"""
pattern = r'^((((?P<hms_grp1>\d*):)?((?P<hms_grp2>\d*):)?((?P<hms_secs>\d+([.]\d*)?)))|' \
'((?P<smu_value>\d+([.]\d*)?)(?P<smu_units>s|ms|us)))$'
match = re.match(pattern, duration)
if match:
groups = match.groupdict()
if groups['hms_secs'] is not None:
value = float(groups['hms_secs'])
if groups['hms_grp2'] is not None:
value += int(groups['hms_grp1']) * 60 * 60 + int(groups['hms_grp2']) * 60
elif groups['hms_grp1'] is not None:
value += int(groups['hms_grp1']) * 60
else:
value = float(groups['smu_value'])
units = groups['smu_units']
if units == 'ms':
value /= 1000.0
elif units == 'us':
value /= 1000000.0
return value
else:
return None

Generate Unique Number in Python within the max limit of Postgres bigint datatype

i have a problem statement where i need to find the unique number in python and save it in database to PostgreSQL .Every time it should generate unique number (i.e should not be repeated)
Also i need to append one prefix as well to the unique number :
The solution I Tried till now :
import time
def generate_unique_reference_number(order_type_id=28):
order_type_prefix = '{:<02}'.format(order_type_id) # 2 digit
current_time = str(int(time.time() * 1000000)) # 16 digit
return int(order_type_prefix + current_time)
numbers = []
numbers_set = set()
for i in range(10000):
num = generate_unique_reference_number(28)
numbers.append(num)
numbers_set.add(num)
print(len(numbers))
print(len(numbers_set))
print(len(numbers) - len(numbers_set))
Its still giving me duplicate values .
Max limit for bigint in postgres server is :
-9223372036854775808 to 9223372036854775807
i can use nano seconds(i.e 19 digits limit same as postgres) ,but i need to append prefix of 2 digits as well .
def generate_unique_reference_number(order_type_id=28):
current_time = str(int(time.time_ns())) # 19 digit
return int(current_time)
even nano seconds approach return duplicates but lesser count .

Difference between dates in Python and print as 00:00:00

So I have a string for a date that I convert to datetime and I want to print the time difference between this date (in utc) and the current time in utc. ie. if it's 1 day and 5 hours ahead, print "01:05:00". Or if it's 6 minutes ahead, print "00:00:06". If the date is in the past, then prepend "-", like "-00:00:06".
So far I have a pretty bad solution that prints something like "0:0:27" if it's 27 minutes away and "-2:-5:-46" if it's 2 days in the past. I would like to have a consistent formatting of xx:xx:xx every time. I've looked at many questions and not even sure if i need to use relativedelta or just datetime.timedelta. Any suggestions?
for ticket in json.loads(data):
ticket_rdate = ticket["time_string"]
if ticket_rdate:
ticket_rdate = datetime.datetime.strptime(ticket_rdate, "%Y-%m-%d %H:%M:%S")
difference = relativedelta(datetime.datetime.utcnow(), ticket_rdate)
ticket["time_until"] = str(difference.days * -1) + ":" + str(difference.hours * -1) + ":" + str(difference.minutes * -1) + ""
sorted_tickets.append(ticket)
return sorted_tickets
This is in python 3.
If you just do
difference = (datetime.datetime.utcnow() - ticket_rdate)
str(difference)
you'll get the output in a consistent format. You can do some string formatting after that to get that in the format that you mentioned.
Considering you're limiting the precision to days, I'd say you don't really need to use relativedelta. If you wanted weeks or months, sure, but you don't.
So keeping that in mind in Py3 you can just do something like:
delta = time1 - time2
delta = delta // timedelta(minutes=1)
print(str(delta))
And let the provided functions do the heavy lifting.
Use string's format method which will let you specify zero padding. Like:
now = datetime.datetime.utcnow()
diff = utcnow - ticket_rdate
negative = '-' if ticket_rdate < utcnow else ''
hours = int(diff.total_seconds() / 3600)
mins = int(diff.total_seconds() / 60)
ticket['time_until'] = '{}{}:{:02}:{:02}'.format(negative, diff.days, hours, mins)
Also, the reason to use relativedelta over timedelta is if you want more flexibility. relativedelta will let you work with other units like months and years, and provides better support for negative deltas.
https://docs.python.org/2/library/datetime.html#timedelta-objects
http://labix.org/python-dateutil#head-ba5ffd4df8111d1b83fc194b97ebecf837add454

fast way to convert datetime to string

I want to know if there is faster way to convert a datetime to a string besides datestr.
datetime is inserted every other lines in my main function (including all of its dependency). I need time at that line of code is executed.
I think my only option is to convert datetime to string faster.
t = datetime('now');
DateString = datestr(t);
I profiled and it seems it is called 12570846 times. It takes 16030.021s in total.
My goal of doing this is get the current time when the line is executed and to match with other information that I get from other program with timestamps. I match two files (one from this MATLAB code and one from my other program) with time stamps.
One way you could do this would be to compare the current time to the time the previous time through the loop. You should only recompute the datestring value if it's different. But we can actually go a step further, because the output of datestr (as you're calling it) only shows seconds. So we can actually ignore microsecond differences.
Example Using now (~128 Seconds)
Below I have an example loop that caches the date string representation. It compares the serial date (in seconds) to the date for which the last date string was generated. Only if it's different is the date string updated.
% Number of seconds in a day to convert the serial date number
secperday = 60 * 60 * 24;
% Store the current time as a reference
lasttime = now;
datestring = datestr(lasttime);
for k = 1:12570846
N = now;
seconds = round(N * secperday);
if ~isequal(lasttime, seconds)
% Update the cache
lasttime = seconds;
datestring = datestr(N);
end
% Use datestring however you want
disp(datestring)
end
Example using clock (~24 seconds)
Another option is to use clock which will give you the different date components in a vector. You can round the last element which represents seconds and milliseconds. By rounding it you suppress the milliseconds. This method seems to be a faster approach.
N = clock;
% Remove milliseconds
N(end) = round(N(end));
lasttime = N;
datestring = datestr(N);
for k = 1:12570846
N = clock;
% Ignore milliseconds
N(end) = round(N(end));
if ~isequal(N, lasttime)
lasttime = N;
datestring = datestr(N);
end
disp(datestring)
end
Funtion-Based Solution
If you want to get the current time as a date string at several points within your code, it is likely much better to create a function which will wrap this functionality. Here is an example of such a function.
function str = getDateString()
% Use persistent variables to cache the current value
persistent lasttime datestring
% Get the current time
thistime = clock;
% Truncate the milliseconds
thistime(end) = floor(thistime(end));
% See if the time has changed since the last time we called this
if ~isequal(thistime, lasttime)
lasttime = thistime;
% Update the cached string reprsentation
datestring = datestr(thistime);
end
str = datestring;
end
You can then call this from anywhere within your code to get the date string and it will only be computed when necessary.
If your loop time is pretty short you might convert the date time every 10th loop or something like that if it will be close enough.

How to improve the speed of STRREAD()?

I have a cell array named 'datetime' as the format below:
2009.01.01 00:00:02.169
this 'datetime' array is 1819833x1 size which is large!!!
I want split it into 2 cell array: 'date' and 'time'.
date='2009.01.01' and time='00:00:02.169'.
So I use the for loop as below:
for i=1:numel(datetime)
[date(i), time(i)] = strread(datetime{i},'%s%s','delimiter',' ');
end
As you can see, it use a loop and the speed is really slow when process such a big data.
I try the code this afternoon, and almost ONE HOUR past, the job is still not done....
So can anyone give me a advice?
Thanks!
So first I would preallocate the date and time, no mather which solution you pick. Next I did some experiments with the following setup
s = '2009.01.01 00:00:02.169';
S = repmat({s}, 100000, 1);
The results are
Using strread
tic, for i=1:numel(S), [~, ~] = strread(S{i},'%s%s','delimiter',' '); end, toc
Elapsed time is 3.694143 seconds.
Using regexp
tic, for i=1:numel(S), [~] = regexp(S{i},'\s+', 'split'); end, toc
Elapsed time is 1.324754 seconds.
Using cellfun
tic, cellfun(#(x) regexp(x, '\s+', 'split'), S, 'UniformOutput', false); toc
Elapsed time is 2.072437 seconds.
As you can see, most of those approaches are very slow. Fortunately, many functions in MATLAB can use cells directly, watch this:
tic, Sresult = regexp(S, '\s+', 'split'); toc
Elapsed time is 0.253819 seconds.
You can now access the result by Sresult{i}{1} or Sresult{i}{2} or simply
date = cellfun(#(x) x{1}, Sresult, 'UniformOutput', false);
time = cellfun(#(x) x{2}, Sresult, 'UniformOutput', false);
Elapsed time is 0.835277 seconds.
Ultra Fast Method
The fastest method I can think of is requiring, that the format is always the same, i.e. the length of each string is equal. In your case, I can imagine it to be true. Then you can use something like this
tic, Sa = cell2mat(S); Sdate = Sa(:,1:10); Stime = Sa(:, 12:end); toc
Elapsed time is 0.060586 seconds.
Here you get another speed factor of about 20!
Here's one approach. Not sure how fast it will be:
datetime = {'2009.01.01 00:00:02.169'
'2009.01.02 00:01:05.169'}; %// example data. Cell array of strings
datetime_split = regexp(datetime, '\s+', 'split'); %// split according to spaces
%// Alternatively: datetime_split = cellfun(#strsplit, datetime, 'uniformoutput', 0);
datetime_split = [datetime_split{:}];
date = datetime_split(1:2:end);
time = datetime_split(2:2:end);
With the above data, this produces
>> date
date =
'2009.01.01' '2009.01.02'
>> time
time =
'00:00:02.169' '00:01:05.169'
So, thanks Robert...your advice really helpful!!!
First, I did preallocation, and the time for loop + strread() combination is reduced to less than 40s with my 'datetime' array which is 1819833x1 size.
So it is the main improvement, we can see that the reduce of memory re-allocation and memory data copying can speed up the process a lot....especially when you perform on a large size of sample data.

Resources