How can I get the first 10 characters of each cell in an array?

I have a cell array (attached) containing dates that look like this:
'1999-01-02T18:24:37Z'
I'd like to get these dates into datenum format, which I can accomplish like this:
ct = char(t{2});
d = datenum(str2double(cellstr(ct(:,1:4))),str2double(cellstr(ct(:,6:7))),str2double(cellstr(ct(:,9:10))));
but that seems awfully convoluted and the str2double calls take a tremendous amount of time for long date lists. All I need are the year, month, and day in datenum format. Is there an elegant way to access only the first ten characters in the cell array t?

4 Comments

Does C{n}(1:10) not work, where C is your cell array and n is an index which you loop over?
Indeed, that works, but looping is even slower.
load samplecells
tic
ct = char(t{2});
d = datenum(str2double(cellstr(ct(:,1:4))),str2double(cellstr(ct(:,6:7))),str2double(cellstr(ct(:,9:10))));
toc
Elapsed time is 0.005271 seconds.
tic
% Using a loop:
d2 = NaN(size(t));
for k = 1:length(t)
d2(k) = datenum(t{k}(1:10));
end
toc
Elapsed time is 0.192488 seconds.
The time difference is quite significant for cell arrays containing millions of dates.
Darn. I gave this another shot, but you might run into memory issues if you have millions of rows. The command A = cat(1,C{1:end}) will produce a char array with row size equal to the number of rows in your data and column length equal to the date size. Then, you can operate on this, so A(:,1:10) will return the first ten characters.
EDIT: I benchmarked it on my PC and this looks like it's quite fast relative to the other two methods:
  • Method 1: (original) 0.35s
  • Method 2: (loop) 32s
  • Method 3: (cat) 0.007s
Hopefully this solves the problem!
EDIT2: I also think this probably won't work if the dates have different widths, so you might need to pad them out if they aren't in fixed size.
Concatenating! I never would have thought of that. Thanks jgg!

Sign in to comment.

 Accepted Answer

This is more readable
>> tic, sdn = cellfun( @(str) datenum( str(1:10), 'yyyy-mm-dd' ), t, 'uni',true ); toc
Elapsed time is 0.012129 seconds.
and this is an order of magnitude faster
tic
str = char(t);
sd2 = datenum( str(:,1:10), 'yyyy-mm-dd' );
toc
Elapsed time is 0.001011 seconds.
They return the same result :-)
And still a bit faster
tic
sd3 = datenum( t, 'yyyy-mm-dd' );
toc
Elapsed time is 0.000927 seconds.
>> all(sd2==sd3)
ans =
1
but is it documented?
>> datestr( datenum( '1999-01-12T18:13:45Z', 'yyyy-mm' ), 31 )
ans =
1999-01-01 00:00:00
>> datestr( datenum( '1999-01-12T18:13:45Z', 'yyyy-mm-ddTHH:MM:SSZ' ), 31 )
ans =
1999-01-12 19:13:45

2 Comments

Interesting! For me this works:
datestr( datenum( '1999-01-12T18:13:45Z', 'yyyy-mm-dd' ), 31 )
ans =
1999-01-12 00:00:00
but your other suggestion does not:
datestr( datenum( '1999-01-12T18:13:45Z', 'yyyy-mm-ddTHH:MM:SSZ' ), 31 )
Error using datenum (line 179)
DATENUM failed.
Caused by:
Error using dtstr2dtnummx
Failed on converting date string to date number.
I'll use the one that works! I didn't know it's possible to specify input format as 'yyyy-mm-dd' when 10 more characters follow. Thanks for the solution, per!
I use R2013b. Here are two more examples, one of which succeeds and another which fails. Not pretty!
>> datestr( datenum( '1999-01-12Z18:13:45', 'yyyy-mm-ddZHH:MM:SS' ), 31 )
ans =
1999-01-12 19:13:45
>> datestr( datenum( '1999-01-12A18:13:45', 'yyyy-mm-ddAHH:MM:SS' ), 31 )
Error using datenum (line 179)
DATENUM failed.
Caused by:
Error using dtstr2dtnummx
Failed on converting date string to date number.
I believe, the idea is that datetime shall replace the old functions. The documentation of the old functions are "trimmed" down. By using "31" I show I used Matlab for some time. Now it's just an ugly magic number.

Sign in to comment.

More Answers (2)

I believe this is what you want.
T = cell2mat(t);
T = cellstr(T(:,1:10));
d1 = datenum(T,'yyyy-mm-dd');
It's clean and fast. In terms of performance, you can compare it to your code that only converts one date, but you shouldn't.

1 Comment

Thanks Paula. I'm still coming to grips with how to index cell arrays. I never quite understand when to use parentheses, when to use curly brackets, when to use cell2str, etc.

Sign in to comment.

Jan
Jan on 10 Dec 2015
Edited: Jan on 10 Dec 2015
You can try FEX: DateStr2Num.mex . The format 31 should work: 'yyyy-mm-dd HH:MM:SS'. It is more than 100 times faster than Matlab's datenum functions.

Categories

Community Treasure Hunt

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

Start Hunting!