How to set regexp expression for HH:MM dd.mm.yyyy format?

Hy, I have a gui where i want to check the user input dateSTOP for the format. The format should be in this order HH:MM dd.mm.yyyy with all the characters used (eg 02:03 01.03.2014 not 2:3 1:3.14). I use this code...
control = regexp(dateSTOP,'[012][0-9]:[0-6][0-9] [1-9]|([012][0-9])|(3[01])).([0][1-9]|1[012]).\d\d\d\d')
if(numel(control)==0)
errordlg('Use format: 05:00 04.09.2014','modal'));
else
...
end
but that also allows the short version. How to rewrite the regexp expression to have all characters?

 Accepted Answer

There is a function that does the parsing for you.
Try
t = datetime(dateSTOP,'InputFormat','hh:mm dd.MM.yyyy')
See
doc datetime

3 Comments

Hey, what do you know, datetime (new in 2014b) actually reject invalid dates unlike datenum. So yes, I would recommend using that.
It's not perfect though, you get a stupid warning. To disable it:
warning('off', 'MATLAB:datetime:FormatConflict_mM');
And the format string is not well thought out. In particular hours have to be capitalised but minutes have to be lowercase, days can be either, month has to be capitalised and year must be lowercase!
t = datetime(dateSTOP,'InputFormat','HH:mm dd.MM.yyyy')
Apparently, the M/m thing is the official standard (of some international body)*, but it causes annoying compatibility issues with the old MATLAB way.
[*] Yes, I asked :)
Thx for brining up this function! didnt know about that... there are so many that sometimes its hard to find the perfect one.

Sign in to comment.

More Answers (2)

First, from a user interface perspective, why don't you want to allow 2:3 1:3:14? In my opinion, user convenience should trump programmer convenience, so make it easy for the user to enter the date even if it's harder to check. You write the code only once, the user uses it numerous time.
Secondly, I wouldn't use a regexp to validate the date. You can do it, but it's going to be a very complicated one. For example, your regexp (once corrected) would still allow abcef 29:69 31.02.9999 ijk. So, what I would do is use a regular expression to extract the numbers and just basic checks and validate the date the traditional way with if tests:
n = regexp(dateStop, '^(\d+):(\d+) (\d+)\.(\d+)\.(\d+)$', 'tokens', 'once'); %just validate it's numbers with right separators and extract numbers
if isempty(n)
error('invalid date');
end
n = num2cell(str2double(n)); %convert strings to numbers and stuff into cell array to distribute on next line
[hour, minute, day, month, year] = n{:}; %distribute cell array to named variables for convenience
if hour < 1 || hour > 23 || minute < 1 || minute > 59 || day < 1 || month < 1 || month > 12 || year < 1
error('invalid date');
end
if (ismember(month, [1 3 5 7 8 10 12]) && day > 31) || (ismember(month, [4 6 9 11]) && day > 30) || (month == 2 && day > 28) %potentially also allow for leap years and add test
error(invalid date');
end
Anyway, with regards to your regular expression, you've misplaced some brackets. Note that the | operator in a regexp take into account the entirety of the expression before and after. Therefore your regular expression allowed '[012][0-9]:[0-6][0-9] [1-9]' or '[012][0-9]' or ... It's both alternative with the operator that you need to enclose in brackets, not each one. Additionally, you seem to be allowing a day that is a single digit. Also, you need to escape the . otherwise they match any characters
The correct regexp would be:
control = regexp(dateSTOP,'[012][0-9]:[0-6][0-9] ([012][0-9]|3[01])\.([0][1-9]|1[012])\.\d\d\d\d')
if isempty(control)
error('...');
end
But as mentioned, this regexp allows abcef 29:69 31.02.9999 ijk. You can eliminate the allowed extra characters by anchoring your regexp (with ^ and $) but to reproduce my two ifs you need:
control = regexp(dateSOP, '^([01][0-9]|2[0-3]):[0-5][0-9] ((([012][0-9]|3[01])\.(01|03|05|07|08|10|12))|(([012][0-9]|30)\.(04|06|09|11))|(([01][0-9]|2[0-8])\.02)\.\d{4}$'); %untested

4 Comments

Thx for your very nice answer.
to your first remark: your right it should be possible to enter any form of date. But i´m calculation later with the date (add some hours) and display the new data again. don´t know how to do that without any specified date string as i change the date to number using datenum(), addtodate() and datestr() again with the specified format='HH:MM dd.mm.yyyy';...
to the second part: thx for the code. ill give it a try...
So be liberal in the input you accept from the user, as per my first example. However, for output be very strict and always write it with the format you've specified, regardless of the format used for input.
Yes, it would be nice to allow also the short input.
But i dont know how to transfer that in my format for the further calculation...
My first example allows short input and give you hours, minutes, day, month and year. That is easily converted into a datevec, datenum, datetime, datestr, or whatever else you want, e.g:
dn = datenum([year month day hour minute 0]);

Sign in to comment.

As an alternative suggestion, one approach is to pass the problem on to datenum: just pass the user's input along to datenum and see if datenum can handle it. If it fails, then the input wasn't OK.
try
% see what datenum does with the input
dateSTOPnum = datenum(dateSTOP,myFormat);
catch
% failure => bad input
errordlg('Use format: 05:00 04.09.2014','modal'));
end

2 Comments

The problem with datenum (and date validation with matlab own functions) is that it will happily accept invalid dates and time
>> datenum('31:66 45.99.1908', 'HH:MM dd.mm.yyyy')
ans =
7.360593375000000e+05
>>datestr(ans)
ans =
05-Apr-2015 08:06:00
You can check for that by converting the datenum back to a datestr (with the same format specification), and comparing to the original string.

Sign in to comment.

Categories

Tags

Asked:

on 17 Oct 2014

Commented:

on 18 Oct 2014

Community Treasure Hunt

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

Start Hunting!