jdl
jdl

Reputation: 6323

Matlab: slow with converting date strings to datenum?

With 100,000 date strings to convert to datenums, Matlab is really slow... 20 seconds!! Is there a faster way of doing this?

%strDay  
%strTime

dblDate = zeros(1, nLines);
for i = 1 : nLines
    dblDate(j) = datenum([strDay{i}, ' ', strTime{i}], 'yy.mm.dd HH:MM:SS.FFF');
    j = j + 1;
end

Upvotes: 2

Views: 2274

Answers (4)

Sam Roberts
Sam Roberts

Reputation: 24127

Internally, datenum does a large amount of fiddling around to process many different date formats. Then it calls the internal function datenummx with different input arguments depending on the date format and the syntax with which you called datenum.

If you know ahead of time which syntax you will be calling datenum with, and which date format you will be using, you can call datenummx directly. Since datenummx is a built-in MEX file, and avoids all the overhead processing, it is typically vastly faster.

Take a look into datenum (type edit datenum) to find out the appropriate way to call datenummx for your application.

(Plus, do all the vectorization that other answers have suggested).

Upvotes: 4

H.Muster
H.Muster

Reputation: 9317

You could try to avoid the loop:

tmp = repmat({' '}, length(strDay), 1);
datenum(cell2mat([strDay  (:), tmp(:),  strTime(:)]))

~edit~
A little bit of benchmarking of all the solutions so far:

% creating some bogus data
a = ones(10000,1).*(now.*rand(10000,1));
str = datestr(a,'yy.mm.dd HH:MM:SS.FFF');
strDay = cellstr(str(:,1:8));
strTime = cellstr(str(:,10:end));

%% jdl's original code
disp('jdl''s original code')
tic
nLines = length(strDay);
dblDate = zeros(1, nLines);
j = 1;
for i = 1 : nLines
    dblDate(j) = datenum([strDay{i}, ' ', strTime{i}]);
    j = j + 1;
end
toc

%% hmuster's solution
disp('hmuster''s solution')
tic
tmp = repmat({' '}, length(strDay), 1);% cell(size(str1));
b = datenum(cell2mat([strDay(:), tmp(:),  strTime(:)]));
toc

%% ThijsW's solution
disp('ThijsW''s solution')
tic
strDay = cell2mat(strDay);
strTime = cell2mat(strTime);

dblDate = datenum([strDay, (' ')*ones(size(strTime)), strTime], 'yy.mm.dd HH:MM:SS.FFF');
toc

% jdl's solution
disp('jdl''s solution')
tic
dblDate = datenum(strDay, 'yy.mm.dd') + ...
    datenum(strTime, 'HH:MM:SS.FFF') - ...
    datenum('00:00:00.000', 'HH:MM:SS.FFF');
toc

This results in:

jdl's original code
   Elapsed time is 19.624597 seconds.
hmuster's solution
   Elapsed time is 4.029291 seconds.
ThijsW's solution
   Elapsed time is 0.183376 seconds.
jdl's solution
   Elapsed time is 0.222996 seconds.

Upvotes: 2

jdl
jdl

Reputation: 6323

This is what I found to reduce time from 20 sec to 2 sec:

dblDate = datenum(strDay, 'yy.mm.dd') + ...
          datenum(strTime, 'HH:MM:SS.FFF') - ...
          datenum('00:00:00.000', 'HH:MM:SS.FFF');

Upvotes: 2

ThijsW
ThijsW

Reputation: 2599

Try it without the for loop. datenum should be able to handle a vectors.

strDay = cell2mat(strDay);
strTime = cell2mat(strTime);

dblDate = datenum([strDay, (' ')*ones(size(strTime)), strTime], 'yy.mm.dd HH:MM:SS.FFF');

Upvotes: 2

Related Questions