Converting number to an actual time string in Matlab - matlab

I want to convert 83012 (an int) to '8:30:12' (a string) in matlab. I couldn't find any clear answer. The real problem is adding the colons. Any help is appreciated.
%Get the start time value from User
str1 = get(handles.StartEditTag, 'string');
newstr1 = erase(str1, ':'); %Take out colons (eg '6:30:00' -> '63000')
startVal = str2num(newstr1); %Convert string to num (eg '63000' -> 63000)
%Get the end time value from the User
str2 = get(handles.EndEditTag, 'string');
newstr2 = erase(str2, ':');
endVal = str2num(newstr2);
roundStart = mod(startVal, 100); %(eg 63000 -> 00)
roundEnd = mod(endVal, 100);
if mod(roundStart, 15) ~= 0
%Round to the nearest multiple of 15 (eg 83027 -> 83030)
startVal = Roundto15(roundStart, startVal); %function I made to round
end
if mod(roundEnd, 15) ~= 0
endVal = Roundto15(roundEnd, endVal);
end
startString = int2str(startVal); %(eg 83030 -> '83030')
endString = int2str(endVal);
I'm taking a time interval from the user and making sure it's in 15 second intervals. This is what I have so far.

Assuming your integer always has 5 or 6 digits
time_int=83012;
time_str=num2str(time_int);
result=strcat(time_str(1:end-4),':',time_str(end-3:end-2),':',time_str(end-1:end));
Edit: A nicer way to do the whole thing
% The string you get from the user
str1 = '16:30:12';
% Extraing hours, minutes, seconds
C1 = textscan(str1,'%d:%d:%d');
% converting the time to seconds
time1_in_seconds = double((C1{1}*3600)+(C1{2}*60)+C1{3});
% rounding to 15 sec
time1_in_seconds_round15 = round(time1_in_seconds/15)*15;
% getting the new hours, minutes and seconds
hours = floor(time1_in_seconds_round15/3600);
minutes = floor((time1_in_seconds_round15 - hours*3600)/60);
seconds = time1_in_seconds_round15 - hours*3600 - minutes*60;
% getting the string
s = sprintf('%d:%d:%d', hours, minutes, seconds);

First do your arithmetic to compute the hours, minutes and seconds, then use string formatting:
s = sprintf('%d:%02d:%02d', hours, minutes, seconds)

Related

convert calendarDuration to duration

Here's something that doesn't make sense to me:
caldays(1); %I get here by running this: between(datetime, datetime+days(1))
%ans =
%
% calendarDuration
%
% 1d
time(caldays(1))
%ans =
%
% duration
%
% 00:00:00
how can I actually convert calendarDurations to durations while preserving days, months and years? I couldn't find this on Mathworks help.
the purpose would be to compare if a certain number of minutes has already passed since a start-date.
thanks
If you want a duration instead of a calendarDuration, you can directly use:
duration = days(1)
To check if a certain amount of minutes have passed since a start_date:
now = datetime
is_5_minutes_passed = (now - start_date) >= minutes(5)
Update:
[d,t] = split(calendarDuration, {'days','time'})
duration = days(d) + t
Now you have a duration array.

Vectorization instead of nested for loops in matlab

I am having trouble vectorizing this for loop in matlab which is really slow.
tvec and data are N×6 and N×4 arrays respectively, and they are the inputs to the function.
% preallocate
sVec = size(tvec)
tvec_ab = zeros(sVec(1),6);
data_ab = zeros(sVec(1),4);
inc = 0;
for i = 1:12
for j = 1:31
inc = inc +1;
[I,~] = find(tvec(:,3)==i & tvec(:,2)== j,1,'first');
if(I > 0)
tvec_ab(inc,:) = tvec(I,:);
data_ab(inc,:) = sum(data( (tvec(:,3) == j) & (tvec(:,2)==i) ,:));
end
end
end
% set output values
tvec_a = tvec_ab(1:inc,:);
data_a = data_ab(1:inc,:);
Every row in tvec represents the timestamp where the data was taken in the same row in the data matrix. Below you can see how a row would look like:
tvec:
[year, month, day, hour, minute, second]
data:
[dataA, dataB, dataC, dataD]
In the main program we can choose to "aggregate" after month, day or hour.
The code above is an example of how the aggregation for the option 'DAY' could happen.
the first time stamp of the day is the time stamp we want our output tvec_a to have in the row for that day.
The data output for that day (row in this case) would then be the sum of all the data for that day. Example:
data:
[data1ADay1, data1BDay1, data1CDay1, data1DDay1;
data2ADay1, data2BDay1, data2CDay1, data2DDay1]
aggregated data:
[data1ADay1 + data2ADay1, data1BDay1 + data2BDay1, data1CDay1+ data2CDay1,
data1DDay1+data2DDay1]
A vectorized version (not fully tested)
[x y] = meshgrid(1:12,1:31);
XY=[x(:) Y(:)];
[I,loc]=ismember(XY,tvec(:,2:3),'rows');
tvec_ab(I)=tvec(loc(loc>0),:);
acm = accumarray(tvec(:,2:3),data);
data_ab(I) = acm(sub2ind(size(acm),tvec(:,2),tvec(:,3)));
I actually found a way to do it myself:
%J is the indexes of the first unique days ( eg. if there is multiple
%data from january 1., the first time stamp from january 1. will be
%the time samp for our output)
[~,J,K] = unique(tvec(:,2:3),'rows');
%preallocate
tvec_ab = zeros(length(J),6);
data_ab = zeros(length(J),4);
tvec_ab = tvec(J,:);
%sum all data from the same days together column wise.
for i = 1:4
data_ab(:,i) = accumarray(K,data(:,i));
end
%set output
data_a = data_ab;
tvec_a = tvec_ab;
Thanks for your responses though

Text file and Matlab

I have a problem doing som changes to a *.txt file.
The data have this format:
11,2003,1,1,9,38,40.38,1
11,2003,1,1,9,47,2.5,1
11,2003,1,1,10,34,43.88,1
11,2003,1,1,10,38,14.5,1
11,2003,1,1,12,47,13.2,1
Where the columns are station number,year, month, day, hour, minute, seconds and precipitation(1 = 0.1 mm)
The times that have precipitation = 0 are not included in the list. This results in hours without rainfall will be absent. For these cases I want to make one entry for the first minute of the hour without rainfall in the New file, to show that there has been made measurements. Like this:
50810,200301010938,0.1
50810,200301010947,0.1
50810,200301011034,0.1
50810,200301011038,0.1
50810,200301011100,0.0 <---- This is what I need to get in the New file
50810,200301011247,0.1
(New station number, date/time, precipitation)
For now I've come up With this:
clear all
data = load('jan-31des_2003.txt'); %opens file with data
fid=fopen('50810_2003','w'); %opens empty file to write
[nrow, ncol] = size(data); %size of data
fprintf(fid,'%5s %12s %5s \r\n','Snr','Dato - Tid','RR_01') %Header
for row = 1:nrow
y = data(row,2); %year
m = data(row,3); % month
d = data(row,4); % date
h = data(row,5); % hour
M = data(row,6); % minute
p = data(row,8); % precipitation
p = p*0.1
end
fclose(fid);
You can use an if command to check if the next hour you are looking at is more than a single hour ahead from the last one. If that's the case you can create a new entry at this point:
if data(row,5) > (data(row-1,5)+1)
y = data(row,2); %year
m = data(row,3); % month
d = data(row,4); % date
h = data(row,5)+1; % hour
M = 00; % minute
p = 0; % precipitation
end
after this part you will need to make check again if there is another 'skipped' hour and so on. You should also replace your for-loop, by a while-loop until you reach the last entry in your dataset.
Try to implement this idea and come back to us with your code in case it didn't work out.

Conversion between time string and second value

I am playing around with the conversion between the time string and the value in second in MATLAB. However, I notice this inconsistency.
startTime = '00:19:00';
N = 15; % minutes
% convert it to the value in sec
startSec = datenum(startTime, 'hh:mm:ss');
% N minutes passed
endSec = startSec+60*N;
% convert it back to the string format
endTime = datestr(endSec, 'hh:mm:ss');
I am expecting my endTime to be '00:34:00', but it turns out to be '00:12:00'.
Why?
I'm surprised your code works at all, because the format strings you passed to datenum are invalid; they need to be uppercase.
Second problem is your assumption that datenum converts the first argument into seconds and returns that value. From the documentation linked above:
DateNumber = datenum(DateString) converts date strings to serial date numbers. ...
A serial date number represents the whole and fractional number of
days from a fixed, preset date (January 0, 0000).
So you need to convert your time offset value also to a DateNumber before adding it to the first result. Here's a fixed version of your code
startTime = '00:19:00';
N = 15; % minutes
% convert it to the value in sec
startSec = datenum(startTime, 'HH:MM:SS');
% N minutes passed
endSec = startSec + datenum(sprintf('00:%02d:00', N), 'HH:MM:SS');
% convert it back to the string format
endTime = datestr(endSec, 'HH:MM:SS');
detenum does not return seconds. Instead, it returns:
the whole and fractional number of days from a fixed, preset date
(January 0, 0000).
startTime = '00:19:00';
N = 15; % minutes
% convert it to the value in sec
startSec = datenum(startTime, 'HH:MM:SS');
startSec = startSec * 24*60*60; % get seconds
% N minutes passed
endSec = startSec+60*N;
% convert it back to the string format
endTime = datestr(endSec / (24*60*60), 'HH:MM:SS');
% will result in
%endTime = 00:34:00
Firstly,
'HH:MM:SS'
is your desired datestring (mm is months). Secondly, datenum doesn't return seconds, it returns days passed from year zero.

extend matrix of time elements in matlab

I've got 1xn matrix called time that I imported from a csv file. Is there any way to extend this matrix by following the time pattern (so that the days per month work)? For example, if I start with.
time =
'"2013-05-01"'
'"2013-05-02"'
'"2013-05-03"'
'"2013-05-04"'
'"2013-05-05"'
And somehow add 5 observations, my matrix becomes:
time =
'"2013-05-01"'
'"2013-05-02"'
'"2013-05-03"'
'"2013-05-04"'
'"2013-05-05"'
'"2013-05-06"'
'"2013-05-07"'
'"2013-05-08"'
'"2013-05-09"'
'"2013-05-10"'
If time is a char matrix:
N = 5; %// how many dates to add
lastdate = datenum(strrep(time(end,:),'"',''),29); %// last available date
time = [time; [repmat('"',N,1) datestr(lastdate+(1:N),29) repmat('"',N,1)] ];
If time is a cell array, just replace last line by
time = [time; mat2cell([repmat('"',N,1) datestr(lastdate+(1:N),29) repmat('"',N,1)],ones(1,N)) ];
This works by reading the last string date, converting to numerical date with datenum, generating N new consecutive dates, and then converting back to string with datestr. The double quotes are dealt with separately.
Example:
>>time = ['"2013-05-04"'; '"2013-05-05"']
time =
"2013-05-04"
"2013-05-05"
gives
>> N = 5; %// how many dates to add
lastdate = datenum(strrep(time(end,:),'"',''),29); %// last available date
time = [time; [repmat('"',N,1) datestr(lastdate+(1:N),29) repmat('"',N,1)] ]
time =
"2013-05-04"
"2013-05-05"
"2013-05-06"
"2013-05-07"
"2013-05-08"
"2013-05-09"
"2013-05-10"
I'm assuming time is a cell array here:
t = cell2mat(time);
n = 5;
t = datenum(t,'"yyyy-mm-dd"'); % using custom format
tdiff = t(end)-t(end-1); % assuming
l = length(t);
newtime = zeros(l+n,1);
newtime(1:l)=t;
newtime(l+1:end) = (t(end)+tdiff):tdiff:(t(end)+tdiff*n);
You can use datestr to convert back to the date format of your choice.