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 commentaires

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.
jgg
jgg le 9 Déc 2015
Modifié(e) : jgg le 9 Déc 2015
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!

Connectez-vous pour commenter.

 Réponse acceptée

per isakson
per isakson le 10 Déc 2015
Modifié(e) : per isakson le 10 Déc 2015
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 commentaires

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.

Connectez-vous pour commenter.

Plus de réponses (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 commentaire

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.

Connectez-vous pour commenter.

Jan
Jan le 10 Déc 2015
Modifié(e) : Jan le 10 Déc 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.

Catégories

Community Treasure Hunt

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

Start Hunting!

Translated by