Convenient handling of datetime function arguments and class properties
12 views (last 30 days)
Show older comments
Hi folks,
At work, we're in the process of adopting Matlab's new datetime type. We're on R2019b currently. Our code previously used primarily datenums and datestr cellstrs or charvecs to represent dates. And we're running in to a couple hitches.
My first thought was to take class properties and function arguments that used to take datenums or datestrs as inputs, and slap a datetime validator on them:
classdef Foo
properties
aDate datetime
end
methods
function fcn(this, dt)
arguments
this
dt datetime
end
end
end
end
But that didn't work out, because Matlab's one-arg datetime(x) constructor interprets numeric inputs as datevecs, not datetimes. This surprised me, because I thought datetimes were more common than datevecs, and there's a more natural correspondence between datenum and datetime than datevec and datetime, because in a datenum array, each element represents a single date value, the same as in a datetime array.
The other hitch we're running in to is that the datetime(str) constructor that takes string inputs hits a try/catch in the ordinary "happy path" course of parsing dates. So if your code commonly uses datetime() to convert strings to dates, dbstop if all error becomes basically unusable in your programs.
>> dbstop if all error
>> datetime('1/1/2020')
Caught-error breakpoint was hit in @datetime/private/guessFormat>tryOneFmt at line 154. The error was:
Error using matlab.internal.datetime.createFromString
Unable to convert the text to datetime using the format 'dd-MMM-uuuu'.
154 t = createFromString(tryStr,fmt,2,tz,locale,pivot); % error, don't return NaT
K>> dbquit
>> datetime('1/1/2020 01:23:45')
Caught-error breakpoint was hit in @datetime/private/guessFormat>tryOneFmt at line 154. The error was:
Error using matlab.internal.datetime.createFromString
Unable to convert the text to datetime using the format 'dd-MMM-uuuu HH:mm:ss'.
154 t = createFromString(tryStr,fmt,2,tz,locale,pivot); % error, don't return NaT
K>> dbstack
> In guessFormat/tryOneFmt (line 154)
In guessFormat (line 43)
In datetime (line 632)
K>> version
ans =
'9.7.0.1319299 (R2019b) Update 5'
K>>
I ended up writing my own todatetime() function to use as a substitue for the datetime() constructor, and use that instead of argument validators. todatetime in MatlabProjectTemplate
classdef foo
properties
aDate datetime
end
methods
function fcn(this, dt)
dt = todatetime(dt);
end
function this = set.aDate(this, aDate)
this.aDate = todatetime(aDate);
end
end
end
How are you all handling function signatures and class property constraints in codebases that have a mix of datetimes and datenums? What are you doing about that try/catch issue?
In your code, prior to datetime, were your date values predominantly datenums or datevecs?
3 Comments
Steven Lord
on 26 Jan 2021
per isakson, I'm not sure what the context is for this comment. Is it referring to a variable in the original post that was renamed or removed on edit?
If you're working with experimental time series and you want the data stored with a time basis of one second, consider using a timetable.
n = datetime('now');
n.Format = n.Format + ".SSSS";
x = (1:5).';
v = sort(n + seconds(5*randn(5, 1)));
tt = timetable(v, x)
tt2 = retime(tt, 'secondly', 'linear')
per isakson
on 26 Jan 2021
Steven Lord, My main intent was to bump an interesting question. Second, I answered the question of the last line of the question.
Answers (1)
Steven Lord
on 26 Jan 2021
But that didn't work out, because Matlab's one-arg datetime(x) constructor interprets numeric inputs as datevecs, not datetimes. This surprised me, because I thought datetimes were more common than datevecs, and there's a more natural correspondence between datenum and datetime than datevec and datetime, because in a datenum array, each element represents a single date value, the same as in a datetime array.
Prior to the introduction of datetime users stored dates and times as serial date numbers that I believe were most often constructed using datenum. If I remember correctly the reasoning was that the most common ways to call datenum to create the serial date numbers were with a date vector or with a text representation S of the date and time (usually along with a format F) so the 1-input constructor of datetime matches the 1-input constructor of datenum. The 2-input (S and F) datenum call becomes a call to datetime with the 'InputFormat' option.
If you have a serial date number, you can call datetime with 'ConvertFrom' to tell MATLAB to convert the serial date number to a datetime.
The other hitch we're running in to is that the datetime(str) constructor that takes string inputs hits a try/catch in the ordinary "happy path" course of parsing dates. So if your code commonly uses datetime() to convert strings to dates, dbstop if all error becomes basically unusable in your programs.
This assumes you call datetime in such a way that its internal helpers need to throw an error (which datetime will effectively rethrow) because they can't determine what you're trying to do.
try % Using this so Answers can evaluate all lines of code in this message
dt = datetime('02-01-2021') % February 1st or January 2nd? Could be either.
catch ME
disp(ME.message)
end
If you know or suspect that the text representation of your datetime is ambiguous, help datetime out by specifying information to make it unambiguous.
dt = datetime('02-01-2021', 'InputFormat', 'dd-MM-yyyy') % unambiguously January 2nd
I ran that last call with dbstop if all error enabled in my desktop MATLAB (I'm not sure if MATLAB Answers evaluation of code will accept debugging commands) and it ran without stopping. No ambiguity means no internal error which means no stopping.
See Also
Categories
Find more on Calendar in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!