- Add 86400 seconds to any negative values
- Use datetimes instead of durations (especially if you have dates associated with your times)
Datatype duration midnight roll over
15 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Christopher McCausland
el 21 de Jul. de 2022
Comentada: Peter Perkins
el 25 de Jul. de 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
0 comentarios
Respuesta aceptada
Cris LaPierre
el 21 de Jul. de 2022
There is no concept of days with a duration variable, so there are 2 options that I could think of.
dur = duration({'23:51:51.000'
'23:52:21.000'
'00:04:51.000'
'00:10:21.000'});
ds = seconds(diff(dur))
% Add one day of seconds to any negative number
ds(ds<0) = ds(ds<0) + 24*60*60
% 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))
seconds(diff(dt))
4 comentarios
Peter Perkins
el 25 de Jul. de 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
datetime("10:39:04",InputFormat="HH:mm:ss") % assumes current date
duration("10:39:04",Format="hh:mm:ss")
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")
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")
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.
Más respuestas (1)
Star Strider
el 21 de Jul. de 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 comentarios
Star Strider
el 21 de Jul. de 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
el 21 de Jul. de 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)
2) get them as a monotonically increasing sequence
dur = dt - dt(1)
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')
Ver también
Categorías
Más información sobre Dates and Time en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!