Datenum behaviour with empty string concatenation

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

Tags:

Matlab

Date