# Datatype duration midnight roll over

4 views (last 30 days)
Christopher McCausland on 21 Jul 2022
Commented: Peter Perkins on 25 Jul 2022
Hello,
I have a table with a series of categorical events and associated timestamp (duration datatype) at which these events happen as shown below. Typically the recordings are overnight. I want to take the timestamps and compute the differance in seconds between each successive timestamp;
Var1 Var2
... ...
'23:51:51.000' 'STAGE - N3'
'23:52:21.000' 'STAGE - R'
'00:04:51.000' 'STAGE - N1'
'00:10:21.000' 'STAGE - N2'
... ...
I have tried a couple of methods with etime() and between() etc. without much success. Seconds() and diff() works as shown below, however at midnight the roll over from 24:59:59 to 00:00:00 causes a large negitive roll over error (shown below). Is there a built in function that can handle this?
seconds(diff(myTable{:,1}))
...
30
-85650
330
30
...
Kind regards,
Christopher

Cris LaPierre on 21 Jul 2022
There is no concept of days with a duration variable, so there are 2 options that I could think of.
1. Add 86400 seconds to any negative values
2. Use datetimes instead of durations (especially if you have dates associated with your times)
dur = duration({'23:51:51.000'
'23:52:21.000'
'00:04:51.000'
'00:10:21.000'});
ds = seconds(diff(dur))
ds = 3×1
30 -85650 330
% Add one day of seconds to any negative number
ds(ds<0) = ds(ds<0) + 24*60*60
ds = 3×1
30 750 330
% use datetimes
dur = datetime({'23:51:51.000'
'23:52:21.000'
'00:04:51.000'
'00:10:21.000'});
d = [0; diff(dur)<0];
dt = dur + days(cumsum(d))
dt = 4×1 datetime array
21-Jul-2022 23:51:51 21-Jul-2022 23:52:21 22-Jul-2022 00:04:51 22-Jul-2022 00:10:21
seconds(diff(dt))
ans = 3×1
30 750 330
Peter Perkins on 25 Jul 2022
"MATLAB seems to consider a time only duration/timedate as having an associated date that was never specified by the user i.e. 01/01/1980 or similar, when this was never given (and cannot be seen or queried by the user?)"
These three things are different:
datetime("10:39:04",Format="HH:mm:ss") % assumes current date
ans = datetime
10:39:04
datetime("10:39:04",InputFormat="HH:mm:ss") % assumes current date
ans = datetime
25-Jul-2022 10:39:04
duration("10:39:04",Format="hh:mm:ss")
ans = duration
10:39:04
The first is often a bad idea, although "cannot be seen or queried by the user?" is overstating it. The second is convenient for interactive use, but a terrible idea for programmatic use for obvious reasons. The third seems like what you want, except I think that you are looking for
d1 = duration(["00:00:00" "08:00:00" "16:00:00" "00:00:00 " "08:00:00" "16:00:00" "00:00:00"],Format="hh:mm:ss")
d1 = 1×7 duration array
00:00:00 08:00:00 16:00:00 00:00:00 08:00:00 16:00:00 00:00:00
to automatically increment by multiples of 24hrs as appropriate, and behave instead "as if" calling something that returns this
d2 = duration(["00:00:00" "08:00:00" "16:00:00" "24:00:00 " "32:00:00" "40:00:00" "48:00:00"],Format="hh:mm:ss")
d2 = 1×7 duration array
00:00:00 08:00:00 16:00:00 24:00:00 32:00:00 40:00:00 48:00:00
It's possible that you are looking to call something that returns something that is like d1 but "knows" that it is monotonic. We generally stay away from that kind of thing because in that case it would be an array that contains values that look like one thing but behave like another. There are a lot of potential pitfalls in doing that.

Star Strider on 21 Jul 2022
Unfortunately, duration values are limited to one day, and reset at midnight. There does not appear to be any workaround for that.
Example —
t = datetime(2022,01,01) + minutes(0:2880).';
s = sin(2*pi*(0:numel(t)-1)/720);
figure
plot(t,s)
grid
tmin = t;
tmin.Format = 'HH:mm:ss';
dt = duration(string(tmin));
figure
plot(dt,s)
grid
I would just keep them as datetime values (or convert them to datetime values), and do any analyses using that result.
.
Peter Perkins on 21 Jul 2022
SS, durations don't wrap at 24hrs, they really don't.
I mean, I know you know this, but just to make sure we're on the same page, datetimes represent points along the real-world time line, and durations represent elapsed time. Another interpretation is that durations repesent time along an "engineering time line" that is not measured with calendar units. In other words, elapsed time from some origin.
"converted my datetime values to duration values (using the string function)": I don't see the code for what I guess was your original stab at that, but if it was something like
dur = duration(string(dt))
then yes, duration will throw an error because the text that string returns is not in a format that the duration ctor understands: it will (almost certainly) have a y/m/d portion, and duration has no notion of calendars.
This
dur = duration(string(dt,'dd:HH:mm:ss'))
is sort of a clever hack around that error, but its kind of an accident: dd means "day of month" in datetime formats, and your datetimes start at 1-Jan, and so you get day numbers from 1 to whatever. dd means "elapsed days" in duration formats. That's why you see the ticks on your second plot like that, starting at 24hr.
There are two recommended ways to get durations from datetimes, depending on what you are wanting to do:
1) chop them off as times of day, i.e. all in [0,24) hrs: timeofday(dt)
dt = datetime(2022,7,22,0:8:48,0,0);
dur = timeofday(dt)
dur = 1×7 duration array
00:00:00 08:00:00 16:00:00 00:00:00 08:00:00 16:00:00 00:00:00
2) get them as a monotonically increasing sequence
dur = dt - dt(1)
dur = 1×7 duration array
00:00:00 08:00:00 16:00:00 24:00:00 32:00:00 40:00:00 48:00:00
So:
t = datetime(2022,01,01) + minutes(0:2880).';
s = sin(2*pi*(0:numel(t)-1)/720);
plot(t,s)
plot(t-t(1),s)
plot(t,s,DatetimeTickFormat='hh:mm:ss')

### Categories

Find more on Dates and Time in Help Center and File Exchange

R2021b

### Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by