Datatype duration midnight roll over

28 views (last 30 days)
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

Accepted Answer

Cris LaPierre
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
  4 Comments
Christopher McCausland
Christopher McCausland on 22 Jul 2022
Hi Peter,
Thanks for the response. I understand what you are saying, and agree with most of it however let me present the problem in a slightly different light.
  1. Why does my data not have an associated date: Data were collected for the formation of a large database. Prior to allowing ‘outside’ use, the identification of personal information and removal process took place. Current best practice - the panel took the decision to remove all date information to ensure anonymity to participants.
  2. I agree what you are saying in terms of datetime and duration, if the time is provided with an associated date. Then this acts like a linear timeline which does not and should not wrap.
  3. However, when given as only a time or duration (with no associated date) wrapping at midnight should occur. Why; If I asked you the difference between 23:55:00 and 00:05:00, you would tell me ten minutes, not -23:00:00, as this is the rotational nature of an analogue clock. I now believe the issue here is really how these values are interpreted. I.e. 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?). I believe the circularity - considering time only - was the point @Star Strider was making too, but I will let him comment on that.
  4. If given a list of timestamps (which do not include dates) which exceed several days IMO there should be an inbuilt input argument to handle this rollover. As without a date, the rollover is inherently guaranteed. This is what I was proposing with D = duration(X,’wrap’). Note, I am only proposing this for instances where a time only (no date) timestamp is given.
  5. Looking further to R, Python and Excel there are several packages to handle this so I do now believe that this is justified.
I hope that makes my rational somewhat clearer, and thankyou for the reply too @Peter Perkins, its always really good to chat with MATLAB staff and experienced users to understand more about MATLAB and see new features and options.
I have implemented what Cris showed and it is working. (Though I do appreciate seeing the old school work around) Noted about etime, I will not use it.
Kind regards,
Christopher
Peter Perkins
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.

Sign in to comment.

More Answers (1)

Star Strider
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.
.
  3 Comments
Star Strider
Star Strider on 21 Jul 2022
@Steven Lord — the duration arrays I’ve worked with, although spanning more than one day (as illustrated in my answer here) do not automatically respect days, so in this example, while the datetime values span two days, the duration values wrap at 24 hours.
When I converted my datetime values to duration values (using the string function), the duration function threw an error saying that it does not recognise 'dd/MM/yyyy HH:mm:ss' format that my datetime vector automatically provided, and specifically suggested using only the 'HH:mm:ss' section of the datetime array.
So, I did.
I have no idea what a workaround for that would be, other than to work only with datetime arrays with data that span multiple days, such as in situations like this.
The duration vector can include multiple days, however the identities of the days themselves are lost —
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 = 'dd:HH:mm:ss';
dt = duration(string(tmin));
figure
plot(dt,s)
grid
.
Peter Perkins
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')

Sign in to comment.

Products


Release

R2021b

Community Treasure Hunt

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

Start Hunting!