I've noticed strange behaviour in the function datenum
with MATLAB R2017a and above:
If you try to run:
date = datenum([""],'yyyymmdd');
We obtain a warning:
Warning: Usage of DATENUM with empty date character vectors or empty strings is not supported. Results may change in future versions.
date =
0x1 empty double column vector
But now if we run:
date = datenum(["","20181012"],'yyyymmdd')
We obtain:
date = 2x1:
737426 % which corresponds to 20190101
737345
So both times we give an empty string to datenum
, but if the array contains multiple strings, the result is different. Why can an empty string be parsed when other strings are present, even another empty string, but not when on its own?
This is probably a bug.
The beginning of the datenum
function contains
arg1 = stringToLegacyText(arg1);
where arg1
is the first input of datenum
. The stringToLegacyText
function does the following, according to its code:
S = STRINGTOLEGACYTEXT(S) converts the string array S to a char row vector, if S is a scalar, or to a cellstr, if S is not a scalar.
That is,
>> stringToLegacyText([""])
ans =
0×0 empty char array
>> stringToLegacyText(["" ""])
ans =
1×2 cell array
{0×0 char} {0×0 char}
>> stringToLegacyText(["" "20181012"])
ans =
1×2 cell array
{0×0 char} {'20181012'}
Later on there is this test:
if isdatestr && isempty(arg1) n = zeros(0,1); warning(message('MATLAB:datenum:EmptyDate')); return; end
which produces the warning you mention if arg1
is empty. The test yields true for the first case above ([""]
), but not for the second (["" ""]
) or third (["" "20181012"]
). So for the second or third cases the function continues to
n = dtstr2dtnummx(arg1,matlab.internal.datetime.cnv2icudf(arg2))
The dtstr2dtnummx
function is undocumented:
>> which dtstr2dtnummx built-in (undocumented)
But it expects a cell array of char vectors as first argument, and somehow gives 737426
for empty char vectors:
>> dtstr2dtnummx({''}, matlab.internal.datetime.cnv2icudf(arg2))
ans =
737426
>> dtstr2dtnummx({'' ''}, matlab.internal.datetime.cnv2icudf(arg2))
ans =
737426
737426
>> dtstr2dtnummx({'' '20181012'}, matlab.internal.datetime.cnv2icudf(arg2))
ans =
737426
737345
I was able to look at how datenum
parses its input arguments in R2018a by typing edit datenum
. One of the first things it does is pass the first argument to a function stringToLegacyText
, which converts it from a string type to either a character array or (and this is key) a cell array of character arrays:
>> import matlab.internal.datatypes.stringToLegacyText % Get helper function
>> stringToLegacyText([""]) % Single empty string
ans =
0×0 empty char array
>> stringToLegacyText(["", "20181012"]) % Array of strings
ans =
1×2 cell array
{0×0 char} {'20181012'}
A short while later in the code, it performs this check:
if isdatestr && isempty(arg1)
n = zeros(0,1);
warning(message('MATLAB:datenum:EmptyDate'));
return;
end
And this is where the discrepancy arises. The isempty
function returns true
for an empty character array (issuing the warning) but returns false for a non-empty cell array, even if that cell array contains all empty objects. For whatever reason, the empty entries default to January 1st, 2019:
>> datestr(737426)
ans =
'01-Jan-2019'
I think the correct fix here would be to update the condition to check for a cell array with any empty entries:
if isdatestr && (isempty(arg1) || (iscell(arg1) && any(cellfun('isempty', arg1))))
n = zeros(0,1);
warning(message('MATLAB:datenum:EmptyDate'));
return;
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With