Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Datenum behaviour with empty string concatenation

Tags:

date

matlab

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?

like image 365
obchardon Avatar asked Jun 18 '19 15:06

obchardon


2 Answers

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
like image 147
Luis Mendo Avatar answered Nov 08 '22 18:11

Luis Mendo


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
like image 35
gnovice Avatar answered Nov 08 '22 16:11

gnovice