Calculate time intervals in an hour
6 views (last 30 days)
Show older comments
Matheus Pacifici
on 27 Sep 2019
Commented: Adam Danz
on 27 Sep 2019
I have a table with 2 columns: start time and end time. For each row the interval interval (end time -start time) represents the duration. I need to find the toal duration per each hour. Note that the time intervals not necessarily are restricted to a specific hour. A part of the table looks like:
Start Time End time
13-Sep-2019 04:12:37 13-Sep-2019 04:16:34
13-Sep-2019 04:18:36 13-Sep-2019 04:33:36
13-Sep-2019 04:33:36 13-Sep-2019 04:48:36
13-Sep-2019 04:48:36 13-Sep-2019 05:03:36
13-Sep-2019 05:03:36 13-Sep-2019 05:18:36
13-Sep-2019 05:18:37 13-Sep-2019 05:33:37
13-Sep-2019 05:33:37 13-Sep-2019 05:48:37
13-Sep-2019 05:48:37 13-Sep-2019 06:03:37
13-Sep-2019 06:03:37 13-Sep-2019 06:18:38
13-Sep-2019 06:18:38 13-Sep-2019 06:33:38
The ideal output would be a table with two columns: hour and total time intervals.
Ex:
Hour Total Duration
13-Sep-2109 04:00:00 X
13-Sep-2109 05:00:00 Y
13-Sep-2109 06:00:00 Z
5 Comments
the cyclist
on 27 Sep 2019
I meant for you to upload the data in a MAT file (using the paper clip icon). It's not very easy to paste those data to create variables in the workspace for testing.
Accepted Answer
the cyclist
on 27 Sep 2019
Edited: the cyclist
on 27 Sep 2019
% Create an input data table
startDateStr = {'2014-05-26 04:44:44';
'2014-05-26 04:45:44';
'2014-05-26 05:44:44';
'2014-05-26 05:45:44';
};
endDateStr = {'2014-05-26 04:44:55';
'2014-05-26 04:45:56';
'2014-05-26 05:44:57';
'2014-05-26 05:45:58';
};
startTime = datetime(startDateStr,'InputFormat','yyyy-MM-dd hh:mm:ss');
endTime = datetime(endDateStr,'InputFormat','yyyy-MM-dd hh:mm:ss');
tbl = table(startTime,endTime);
% Find the unique hours, and the index to those hours
hourOfDay = dateshift(tbl.startTime,'start','hour');
[Hour,~,whichHour] = unique(hourOfDay);
% Find the durations (in seconds, but could be something else)
durationsInSeconds = seconds(tbl.endTime - tbl.startTime);
% Find the total duration for each of the unique hours
TotalDuration = accumarray(whichHour,durationsInSeconds);
% Put the result in a table
output = table(Hour,TotalDuration)
6 Comments
Adam Danz
on 27 Sep 2019
If a starttime and endtime have two different hours (03:59 to 04:59), the entire duration will be assigned to the first hour (3:00) since "whichHour" is based on the starting hour. So your hunch is correct that this would cause those simptoms (along with the span >24hr).
More Answers (1)
Adam Danz
on 27 Sep 2019
Edited: Adam Danz
on 27 Sep 2019
I've made lots of comments to explain what's going on. But here's a summary.
This approach interpolates each start:end time to second-resolution, combines all of those vectors into one, and applies unique() to get rid of any duplicates. That results in a single long vector of timestamps at 1-second-resolution that cover every start:end without overlap. Then we use histcounts() to count the number of seconds per hourly bin. The hourly bins span across days (or months or years) and covers the entire range of your data. The number of seconds per hour are converted to number of minutes per hour.
The result is a table displayed below.
The "Minutes" column can also be displayed in "durations". You'll see a commented line in the code that makes that conversion, if desired.
% Read in data
T = readtable('RepoInSeatHistory.xlsx');
T.startTime = datetime(T.startTime,'InputFormat','yyyy-MM-dd HH:mm:ss +0000');
T.endTime = datetime(T.endTime,'InputFormat','yyyy-MM-dd HH:mm:ss +0000');
% Determine the min and max datetime to the hour (rounding up/down)
minHr = min(dateshift(T.startTime,'start','hour'));
maxHr = max(dateshift(T.startTime,'end','hour'));
% Create bins that span every day/hour (this allows for spans >24 hrs)
hrBins = minHr : hours(1) : maxHr;
% Interpolate all start:end to second-resolution
dtInterpCell = arrayfun(@(i)T.startTime(i) : seconds(1) : T.endTime(i), 1:size(T,1),'UniformOutput',false);
dtInterp = dateshift([dtInterpCell{:}],'end','second'); %a long vector of all start:end in second-resolution
% Remove any duplicates (this avoids problem of overlapping start-end values)
dtInterp = unique(dtInterp); %note, the order of the datetimes doesn't matter
% Now simply use histcounts to determine the number of seconds within hourly bins
% that potentially span multiple days
secondsPerHour = histcounts(dtInterp,hrBins);
% Convert to minutes/hr
% This may result in decimals that represent partial minutes since we're measuring
% at second-resolution. If that's not desired, you can use floor() or ceil() to
% round down or up.
MinutsPerHour = secondsPerHour/60;
% MinutsPerHour = minutes(secondsPerHour/60); % Alternative: minute durations
% Put results in a table
hrBins(end) = []; %remove last edge
Tout = table(hrBins(:), MinutsPerHour(:),'VariableNames',{'HourBins', 'Minutes'});
Result
Tout =
19×2 table
HourBins Minutes
____________________ _______
12-Sep-2019 21:00:00 29.333
12-Sep-2019 22:00:00 60
12-Sep-2019 23:00:00 60
13-Sep-2019 00:00:00 58
13-Sep-2019 01:00:00 56
13-Sep-2019 02:00:00 57.983
13-Sep-2019 03:00:00 60
13-Sep-2019 04:00:00 57.983
13-Sep-2019 05:00:00 60
13-Sep-2019 06:00:00 60
13-Sep-2019 07:00:00 60
13-Sep-2019 08:00:00 60
13-Sep-2019 09:00:00 60
13-Sep-2019 10:00:00 60
13-Sep-2019 11:00:00 60
13-Sep-2019 12:00:00 60
13-Sep-2019 13:00:00 32.517
13-Sep-2019 14:00:00 48.2
13-Sep-2019 15:00:00 9.4833
2 Comments
Adam Danz
on 27 Sep 2019
I wonder what release of Matlab you are using. Histcounts does take datetime inputs (at least in r2019a and b). Search for "datetime" on the histcounts documentation page:
Glad I could help!
See Also
Categories
Find more on Dates and Time in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!