Odd behavior using datetime

4 views (last 30 days)
Gonzalo
Gonzalo on 3 Sep 2024
Edited: dpb on 5 Sep 2024
I am using the datetime function to convert numbers into dates. For example:
datetime(num2str(2072016),'InputFormat','ddMMyyyy')
ans = datetime
02-Jul-2016
This works as expected, but -for some unknown reason to me- this fails on certain dates, e.g.:
datetime(num2str(4072016),'InputFormat','ddMMyyyy')
Error using datetime (line 667)
Unable to convert '4072016' to datetime using the format 'ddMMyyyy'.
Why does this happen? Am I doing something wrong? Is this a bug?
However, if I only specify one 'd' on my InputFormat instead of 2, this works as expected:
datetime(num2str(4072016),'InputFormat','dMMyyyy')
I am aware of other ways to input numbers to use the datetime function, but in my case this is the way that takes the less number of lines in my code. Also, a workaround for this should not be necessary since this way of converting a string into a date should work regardless of the date in question.
My MATLAB version is 2024a. Although I do not know whether this is a thing in other versions as well.
Thanks!

Answers (4)

dpb
dpb on 3 Sep 2024
Edited: dpb on 5 Sep 2024
I'm surprised the first works; it shouldn't either.
See the doc for datetime <time formats>. As it notes,
d Day of the month, using one or two digits
dd Day of the month using two digits
The date strings should be
datetime('04072016','InputFormat','ddMMyyyy')
ans = datetime
04-Jul-2016
to use 'dd'.
If you do not want to incorporate the leading zero on days, then you want/need the single-letter date format string. Note, by the way, the same rule holds for months, 'M' and 'MM' and the various time fields as well. Read all of the documentation!!! :)
Also note that neither
num2str(04072016)
ans = '4072016'
string(04072016)
ans = "4072016"
keep the nonsignificant leading zero if you are reading date strings in as numeric; you would need a format string to convert them to include such.
ADDENDUM/ERRATUM:
While the datetime documentation format description describes that the single-letter form will accept either one- or two-digit days/months, datetime seems unable to convert the two-digit form given the single digit format. I think this is either a bug or the documentation should be corrected to reflect actual behavior. The description section of the documentation using 'infmt' states that all strings must be the same format, but the input array are all compliant with the one- or two- character and the input format string provided that is two-digits for month and four for year.

Star Strider
Star Strider on 4 Sep 2024
If there are more than one value that you want to convert, perhaps something like this —
date = [4072016 12072016];
sdate = cellfun(@num2str, num2cell(date), 'Unif',0)
sdate = 1x2 cell array
{'4072016'} {'12072016'}
for k = 1:size(sdate,2) % Zero-Pad 'date' Values With Odd Numbers Of Characters
if rem(numel(sdate{k}),2) ~= 0
sdate{k} = ['0' sdate{k}];
end
end
Out = datetime(sdate.', InputFormat="ddMMyyyy")
Out = 2x1 datetime array
04-Jul-2016 12-Jul-2016
Any leading zeros would be left off of a date specified only as a number.
.
  3 Comments
Stephen23
Stephen23 on 4 Sep 2024
Edited: Stephen23 on 4 Sep 2024
vec = [4072016 12072016];
str = compose('%08i',vec(:))
str = 2x1 cell array
{'04072016'} {'12072016'}
dpb
dpb on 4 Sep 2024
Edited: dpb on 4 Sep 2024
Another good alternative, @Stephen23!
vec = [4072016 12072016];
str = num2str(vec(:),'%08i')
str = 2x8 char array
'04072016' '12072016'
also works, but returns a char() array unless cast to cellstr for datetime()
The arithmetic to convert to y,m,d arrays is not bad, either
y=rem(vec,10000);
m=fix(rem(vec/10000,100));
d=fix(rem(vec/1000000,100));
datetime(y,m,d).'
ans = 2x1 datetime array
04-Jul-2016 12-Jul-2016

Sign in to comment.


dpb
dpb on 4 Sep 2024
Have a better mousetrap, I think...
dates = string([4072016 2072016 12072016]).';
dt=datetime(pad(dates,8,'left','0'),'InputFormat','ddMMyyyy')
dt = 3x1 datetime array
04-Jul-2016 02-Jul-2016 12-Jul-2016
using the new(ish) strings class functionality to pad the shorter rows -- same end result as @Star Strider's with the explicit code, of course.
BTW, I'd caution against using date as a variable, it is a MATLAB-supplied function that gets aliased and might be confusing later in code dealing with time and dates...

dpb
dpb on 4 Sep 2024
Another alternative without converting the numeric values to strings...
dates = [4072016 2072016 12072016].';
y=rem(dates,10000);
m=fix(rem(dates/10000,100));
d=fix(rem(dates/1000000,100));
datetime(y,m,d)
ans = 3x1 datetime array
04-Jul-2016 02-Jul-2016 12-Jul-2016
Or, the date vector can be passed if more convenient
ymd=[y m d];
datetime(ymd)
ans = 3x1 datetime array
04-Jul-2016 02-Jul-2016 12-Jul-2016

Products


Release

R2024a

Community Treasure Hunt

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

Start Hunting!