Is there a Matlab function to convert elapsed seconds to HH:MM:SS format? - matlab

I would like to convert an elapsed number of seconds into HH:MM:SS format. Is there a built-in function for this, or do I have to write my own?

datestr is probably the function you are looking for. Express your time interval as a decimal fraction of a day, for example:
>> datestr(0.25, 'HH:MM:SS.FFF')
ans =
06:00:00.000
That is, one quarter of a day is 6 hours. If you want to transform intervals longer than a day this way you'll have to adjust the second argument, which formats the function's output, for example:
>> datestr(2.256789741, 'DD:HH:MM:SS.FFF')
ans =
02:06:09:46.634
The first argument to datestr could also be either a date vector or a date string rather than a date serial number. This should get you started, if you have problems ask another question or edit this one.
--
To convert a time in seconds using datestr, divide the value by 24*60*60.
Sample:
t1 = toc;
timeString = datestr(t1/(24*60*60), 'DD:HH:MM:SS.FFF');

I don't know a built-in function. However, there is a SEC2HMS on Matlab's File Exchange. Basically, it boils down to something like
function [hours, mins, secs] = sec2hms(t)
hours = floor(t / 3600);
t = t - hours * 3600;
mins = floor(t / 60);
secs = t - mins * 60;
end
If you also want to have it formatted, use a printf:
function hms = sec2hms(t)
hours = floor(t / 3600);
t = t - hours * 3600;
mins = floor(t / 60);
secs = t - mins * 60;
hms = sprintf('%02d:%02d:%05.2f\n', hours, mins, secs);
end
sec2hms(69.9904)
ans =
00:01:09.99

If you want to get the hours, minutes and seconds as doubles consider the following line of code:
seconds = 5000;
hms = fix(mod(seconds, [0, 3600, 60]) ./ [3600, 60, 1])
hms =
1 23 20
This line of code is more than 100 times faster than using the built-in datestr funciton.
nIterations = 10000;
tic
for i = 1:nIterations
hms = fix(mod(seconds, [0, 3600, 60])./[3600, 60, 1]);
end
sprintf('%f ms\r', toc / nIterations * 1000)
gives 0.001934 ms.
tic
for i = 1:nIterations
datestr(seconds/24/3600, 'HH:MM:SS');
end
sprintf('%f ms\r', toc / nIterations * 1000)
gives 0.209402 ms.

If you want from original second input, just convert it to a fraction of the day:
datestr(25/24/3600, 'DD-HH:MM:SS')
ans =
00-00:00:25
Just gives it for 25 seconds (as from tic/toc)

Related

Converting Epoch to Date in Matlab with fractions seconds

I have an array of Epoch times that include fractional (nanoseconds). I have reviewed Converting Epoch to Date in Matlab but still cannot seem to convert to the correct date. I must be missing something simple.
Example data:
1548348497.191261
I am using the code in the link above.
time_unix_nanos = 1548348497.191261;
millis = round(time_unix_nanos);
nanos = time_unix_nanos - 1e6 * millis;
time_matlab = round(864e5 * (millis - datenum('1970', 'yyyy')));
s = [datestr(time_matlab, 'yyyy-mm-dd hh:mm:ss.FFF;), num2str(nanos)];
fprintf('s: = %f\n',s);
Two desired outputs
Full date format: yyyy-mm-dd HH:mm:ss.SSS
Just time format: HH:mm:ss.SSS
Thanks in advance!
It seems you've mistaken the conversion of unixtime to matlab time with matlab time to unixtime.
time_unix_nanos = 1548348497.191261;
millis = round(time_unix_nanos / 1e6); % You had also a /1e6 missing here
nanos = time_unix_nanos - 1e6 * millis;
% The following line converts unix time to matlab time. The line you used was doing the opposite
time_matlab = datenum('1970', 'yyyy') + millis / 864e5;
% First desired date format
s1 = [datestr(time_matlab, 'yyyymmdd HH:MM:SS.FFF;'), num2str(nanos)]
% Second desired date format
s2 = [datestr(time_matlab, 'HH:MM:SS.FFF;'), num2str(nanos)]
gives
>> s1
'19700101 00:00:01.548;348497.1913'
>> s2
'00:00:01.548;348497.1913'

Convert milliseconds into hours and plot

I'm trying to convert an array of milliseconds and its respective data. However I want to do so in hours and minutes.
Millis = [60000 120000 180000 240000....]
Power = [ 12 14 12 13 14 ...]
I've set it up so the data records every minute, hence the 60000 millis (= 1 minimte). I am trying to plot time on the x axis and power on the y. I would like to have the x axis displayed in hours and minutes with each respective power data corresponding to its respective time.
I've tried this
for i=2:length(Millis)
Conv2Min(i) = Millis(i) / 60000;
Time(i) = startTime + Conv2Min(i);
if (Time(i-1) > Time(i) + 60)
Time(i) + 100;
end
end
s = num2str(Time);
This in attempt to turn the milliseconds into hours starting at 08:00 and once 60 minutes have past going to 09:00, the problem is plotting this. I get a gap between 08:59 and 09:00. I also cannot maintain the 0=initial 0.
In this scenario it is preferable to work with datenum values and then use datetick to set the format of the tick labels of your plot to 'HH:MM'.
Let's suppose that you started taking measurements at t_1 = [HH_1, MM_1] and stopped taking measurements at t_2 = [HH_2, MM_2].
A cool trick to generate the array of datenum values is to use the following expression:
time_datenums = HH_1/24 + MM_1/1440 : 1/1440 : HH_2/24 + MM_2/1440;
Explanation:
We are creating a regularly-spaced vector time_datenums = A:B:C using the colon (:) operator, where A is the starting datenum value, B is the increment between datenum values and C is the ending datenum value.
Since your measurements have been taken every minute (60000 milliseconds), then the increment between datenum values should be of 1 minute too. As a day has 24 hours, that makes 1440 minutes a day, so use B = 1/1440 as the increment between vector elements, to get 1 minute increments.
For A and C we simply need to divide the hour digits by 24 and the minute digits by 1440 and sum them up like this:
A = HH_1/24 + MM_1/1440
C = HH_2/24 + MM_2/1440
So for example, if t_1 = [08, 00], then A = 08/24 + 00/1440. As simple as that.
Notice that this procedure doesn't use the datenum function at all, and still, it manages to generate a valid array of datenum values only taking into consideration the time of the datenum, without needing to bother about the date of the datenum. You can learn more about this here and here.
Going back to your original problem, let's have a look at the code:
time_millisec = 0:60000:9e6; % Time array in milliseconds.
power = 10*rand(size(time_millisec)); % Random power data.
% Elapsed time in milliseconds.
elapsed_millisec = time_millisec(end) - time_millisec(1);
% Integer part of elapsed hours.
elapsed_hours_int = fix(elapsed_millisec/(1000*60*60));
% Fractional part of elapsed hours.
elapsed_hours_frac = (elapsed_millisec/(1000*60*60)) - elapsed_hours_int;
t_1 = [08, 00]; % Start time 08:00
t_2 = [t_1(1) + elapsed_hours_int, t_1(2) + elapsed_hours_frac*60]; % Compute End time.
HH_1 = t_1(1); % Hour digits of t_1
MM_1 = t_1(2); % Minute digits of t_1
HH_2 = t_2(1); % Hour digits of t_2
MM_2 = t_2(2); % Minute digits of t_2
time_datenums = HH_1/24+MM_1/1440:1/1440:HH_2/24+MM_2/1440; % Array of datenums.
plot(time_datenums, power); % Plot data.
datetick('x', 'HH:MM'); % Set 'HH:MM' datetick format for the x axis.
This is the output:
I would use datenums:
Millis = [60000 120000 180000 240000 360000];
Power = [ 12 14 12 13 14 ];
d = [2017 05 01 08 00 00]; %starting point (y,m,d,h,m,s)
d = repmat(d,[length(Millis),1]);
d(:,6)=Millis/1000; %add them as seconds
D=datenum(d); %convert to datenums
plot(D,Power) %plot
datetick('x','HH:MM') %set the x-axis to datenums with HH:MM as format
an even shorter approach would be: (thanks to codeaviator for the idea)
Millis = [60000 120000 180000 240000 360000];
Power = [ 12 14 12 13 14 ];
D = 8/24+Millis/86400000; %24h / day, 86400000ms / day
plot(D,Power) %plot
datetick('x','HH:MM') %set the x-axis to datenums with HH:MM as format
I guess, there is an easier way using datetick and datenum, but I couldn't figure it out. This should solve your problem for now:
Millis=6e4:6e4:6e6;
power=randi([5 15],1,numel(Millis));
hours=floor(Millis/(6e4*60))+8; minutes=mod(Millis,(6e4*60))/6e4; % Calculate the hours and minutes of your Millisecond vector.
plot(Millis,power)
xlabels=arrayfun(#(x,y) sprintf('%d:%d',x,y),hours,minutes,'UniformOutput',0); % Create time-strings of the format HH:MM for your XTickLabels
tickDist=10; % define how often you want your XTicks (e.g. 1 if you want the ticks every minute)
set(gca,'XTick',Millis(tickDist:tickDist:end),'XTickLabel',xlabels(tickDist:tickDist:end))

How can I stop Matlab rounding decimals when subtracting Datetime variables

I am having some issues in Matlab to do with rounding errors with datetime typed variables.
I have an array, lets call it 't', and it is of type datetime.
Say for example, t(2) = 00:01:35.6889999, and t(1) = 00:01:35.3549042.
If I try to do t(2)-t(1), all I get is an answer of type 'duration' of 00:00:00 .
I would like to find the difference between these times and keep the precision!
Any help, or directions to links that directly cater/relate to an issue like this would be appreciated! I'm not that familiar with using datetime & duration typed variables in Matlab!
Extra info: I am using Matlab R2017a
Edit: I have Format Long; written in my script.
Precision is not being lost, you just need to change the display format.
The default display format is HH:MM:SS:
>> A = duration(0, 0, 0, 1.25) % 1.25 MS
A =
duration
00:00:00
You can modify the format to display fractional parts. For example:
>> A.Format = 's' % Seconds only
A =
duration
0.00125 sec
>> A.Format = 'hh:mm:ss.SSSSSSSS' % HMS, up to 9 fractional second digits
A =
duration
00:00:00.00125000
You can also use helper functions like milliseconds or seconds to return double arrays:
>> seconds(A)
ans =
0.0013
>> milliseconds(A)
ans =
1.2500
This should work if only seconds vary in the two dates
second(t(1))-second(t(2))
The duration object actually has the proper precision. It just doesn't display it unless you set the format.
>> dur = duration(t(2) - t(1), 'Format', 's')
dur =
duration
0.3341 sec
Whether you set the format or not, you can grab the seconds directly from the duration object.
>> format long
>> seconds(dur)
ans =
0.334095700000000
>> seconds(t(2) - t(1))
ans =
0.334095700000000

If-Else Statement of Time in Matlab

Hi I successfully made the code in which I have the input of my computer time and date that goes like this
function [Y, M, D, H, MN, S] = fcn()
coder.extrinsic('now');
coder.extrinsic('datevec');
Y = 0;
M = 0;
D = 0;
H = 0;
MN = 0;
S = 0;
[Y, M, D, H, MN, S] = datevec(now);
end
it works perfectly fine. Then I tried to make another block for the controller that will have an output of 1 between 7AM-5PM and output 0 if not within this time and my code goes like this
function y = fcn(u)
u = datestr(7:00AM:5:00PM)
if u = datestr(7:00AM:5:00PM)
y=1;
else
y=0;
end
but an error occured. Please help me figure out what's wrong. Thank you
First of all, the first function that you've made is already built in MATLAB as clock.
Regarding your problem, there are plenty of possible approaches to the problem, but I think the easiest one would be count seconds passed from the beginning of the day.
Using clock command you would get vector of current time in format: [year month day hour minute second]. So, the time passed from the beginning of day is 3600*time(4) + 60*time(5) + time(6), i.e. 3600 times hours plus 60 times minutes and plus seconds. From 00:00:00 to 7:00:00 7*3600 seconds passed. Similarly from 00:00:00 to 17:00:00 17*3600 seconds passed. Therefore, you can just compare these values to find whether it's between 7AM and 5PM or not:
function y = IsBetween5AMand7PM
time = clock;
current = 3600*time(4) + 60*time(5) + time(6); %seconds passed from the beginning of day until now
morning = 3600*7; %seconds passed from the beginning of day until 7AM
evening = 3600*17; %seconds passed from the beginning of day until 5PM
y = current > morning && current < evening;
Hope that helps.

Calculate week numbers in matlab

I have an annual time series where measurements are recorded at hourly intervals:
StartDate = '2011-01-01 00:00';
EndDate = '2011-12-031 23:00';
DateTime=datevec(datenum(StartDate,'yyyy-mm-dd HH:MM'):60/(60*24):...
datenum(EndDate,'yyyy-mm-dd HH:MM'));
dat = 2+(20-2).*rand(size(DateTime,1),1);
I would like to calculate the mean 24 hour cycle for each week of the year i.e. for week 1, day of year 1 to 7 I want to calculate the average 00:00, 01:00,... and so on so eventually I will end up with 52, 24 hour series i.e. one for each week of the year. Matlab does have a function called 'weeknum' which returns the week number from a given seriel date number, however, this function is in the financial toolbox. Can anyone suggest an alternative method for finding week number?
Maybe this can be of help (I'm using the current date and time as an example):
c = datevec(datestr(now));
week_num = ceil(diff(datenum([c(1), 1, 1, 0, 0, 0; c])) / 7)
I'm not sure how this solution handles edge cases properly, but I think it's a good place to start.
You can also verify it with this website that tells the current week number.
Applying this to your example can be done, for example, like so:
weeknum = #(v)ceil(diff(datenum([v(1), 1, 1, 0, 0, 0; v(:)'])) / 7);
arrayfun(#(n)weeknum(DateTime(n, :)), 1:size(DateTime, 1))'
According to Wikipedia, ISO week number is calculated like this.
I did it for today as an example.
offsetNotLeap = [0 31 59 90 120 151 181 212 243 273 304 334];
offsetLeap = [0 31 60 91 121 152 182 213 244 274 305 335];
todayVector = datevec(today);
todayNum = today;
ordinalDay = offsetLeap(todayVector(2)) + todayVector(3);
dayOfTheWeek = weekday(todayNum);
weekNumber = fix((ordinalDay - dayOfTheWeek + 10)/ 7)
weekNumber =
51
I didn't do the checks for 0 and 53 cases.
Also note that MATLAB's weekday function gives Sunday's index as 1, so if you want to make Monday's index 1, you need to do some adjustments. ISO says that Monday should be 1.
Just a simple weekday function with Monday as the first day of the week:
function [ daynumber,dayname ] = weekd( date )
%WEEKD Returns the day number and day name based on the input date
% First day of week
% -----------------
% The first day of the week is Monday.
%
% Parameter
% ---------
% date = Input date -> format: dd.mm.yyyy / Example: 21.11.2015
[dn,dayname] = weekday(datenum(date,'dd.mm.yyyy'));
if dn == 1;
daynumber = 7;
elseif dn >= 2 && dn <= 7
daynumber = dn - 1;
else
error('Invalid weekday number.'),
end
end
although some time has past since you posted your question, I want to give an additional answer, if people will have the same issue as me. As HebeleHododo already indicated, there exists a rule posted on Wikipedia how to compute the ISO week number. But anyhow, I wasn't able to find a generic code snippet for it.
Therefore, I developed the following generic method which is able to take vectors, matrices or single values of arbitrary datetimes with arbitrary reference years. Appreciate to read any constructive feedback. I successfully ran it on MATLAB R2017a and tested it further for some edge cases.
function week_num = get_week_num(dtimes)
dnums = datenum(dtimes);
firsts = datenum(year(dtimes), 1, 1);
ordinal = floor(dnums - firsts);
wday = weekday(dtimes) - 1;
wday(wday == 0) = 7;
week_num = floor((ordinal + wday + 10) / 7);
end