I am using a calenderExtender control to get a date from user. The text box can be edit manually by the user. I am using a RegularExpressionValidator to validate Input date. The input format i need is
MMM dd, yyyy
Now i am using a regular expression shown below to validate date
((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec)){1}\s?\d{1,2},\s?\d{4}
It works fine. But it do not check the input date is less than 28,30 or 31 based on month . example :the month December have 31 days. If the user entered greater than 31 ,the expression must caught that.
Any ideas to achieve this using regular exptression??
The validation that you want to do (excluding invalid date ranges based on month) is really unsuited for a regular expression. You should parse the month, date, and year, and then do your validation based on the parsed values. Trying to do it via a regex will be painful and difficult to maintain.
Alternately, have you considered just using DateTime.Parse?
If you think that's bad, just wait till you try supporting leap years. Yep, as is usually the case with "how do I do (insert difficult task) with regex?" questions, the best approach is to just avoid regular expressions entirely. Can you use a RangeValidator instead? Otherwise, as JSBangs noted, you could use a custom validator with DateTime's parsing methods.
Related
i'm trying to parse a user input of a date to a MySQL Timestamp format (YYYY-MM-DD).
User input could be something like:
input - wanted conversion
1) January - ThisYear-01-01, ThisYear-01-31
2) February 2017 - 2017-02-01, 2017-02-28
3) 01. April 2016 - 2016-04-01
4) 5.4.15 - 2015-04-05
P.S.:
The examples above are the suggested formats that we want to support (supporting only some of them would be also fine).
The users are not random or international, they will always write and understand dates in this format (Day Month Year).
Handling the missing year entry or the zero (like 5/4 in #4) isn't a problem but finding a proper way to handle the mentioned possible date input formats (DD MM YY, DD MM, DD Month, Month, Month YY, DD Month YY....etc.) with something that doesn't look very ugly and long in code is a little bit hard for me to imagine.
P.S.:
D,DD,MM,YY,YYYY are short for the numerical input.
Month is for the word input variant.
Could you please tell me if there is anything that could help me to make this process easier/more readable or at least point me to the right direction?
Thanks
Update #1:
By looking again to my question above i see that it's missing some background information, but i didn't want to write a long description to it, just only to the wanted function. Sorry.
So here are some general infos about the Program:
The Program is a Chatbot written in C# (UWP) which accepts a user request in natural language and give back the requested info (if recognized) from a mySQL DB (DB is based on a OSTicket support system).
Internally we send the user input to LUIS.ai to get it recognized and we get back the intents and entities from the service, which we then parse to a SQL Query and send it to the DB.
The results from the DB are then sent back to the user.
Many parsed queries work perfectly, that's why i want now to extend it by letting the user give a certain date in the request (e.g. give me all the support tickets from April).
What i only want is to take this new input "April" and convert it to a MySQL TimeStamp format, so that it would be also recognized from MySQL.
My current approach is to build a string like this:
string convertedTS = year + "-" + month + "-" + day;
And using 3 functions try to detect all three variables. But that's it for now.
E.g. "give me all the tickets from April":
April (recognized from LUIS AI as given date) will be converted to (04)
Year will be taken from
DateTime.Today.Year
and inserted too (2018-04)
The first day is always 01 and the last day of the month will be:
DateTime.Today.Year
Final Query from the example:
select ..........between '2018-04-01' AND '2017-04-30'
If you're worried about formatting the years, months, days, etc, you're doing it wrong. You have C#, and you have a date string from the user. Your concern is getting that string into a C# DateTime value. MySql has no part of this.
Once you have the DateTime value, let your connection provider worry about formatting via parameterized queries:
DateTime d = GetMyDateTimeValueFromUser();
string sql = "pretend SQL comnand with a datetime #variable";
using (var cn = new MySqlConnection("connection string here"))
using (var cmd = new MySqlCommand(sql, cn))
{
cmd.Parameters.Add("#variable", MySqlDbType.Timestamp).Value = d;
cn.Open();
//pick one.
cmd.ExecuteReader();
cmd.ExecuteNonQuery();
}
No special SQL format needed. If you're not using parameterized queries, you're not doing it right! This applies to much more than just DateTime values. All data used in an SQL statement should be handled this way. This has security and performance implications that go way beyond simple date values. Go parameters, or go home (I mean that: go home. Don't write bad code. We don't need any more.)
As it applies to the question, it means the problem is entirely about parsing a string to a C# DateTime value. The next step of moving this data to SQL is just not relevant. Thankfully, .Net has some options for you here. Specifically, take a look at the Parse family of functions, including:
DateTime.Parse()
DateTime.TryParse()
DateTime.ParseExact()
DateTime.TryParseExact()
The latter two allow you specify a set of allowed formats that can match the formats actually seen by your system. NuGet can be a further resource in this area.
What's that, you say? You want to allow the user to input anything? That just won't work. Period. Real humans can and will come up with far more ways to enter a date than you could possibly ever handle. Not to mention you need to know what to do when a British citizen inputs the value 1/2/2018 into your system, because that person almost certainly believes it means February 1, 2018, and not January 2. Cultural differences like this mean it is impossible to accept date inputs without some kind of contextual input filter on the front end. You must look to your user interface to help your users create values your code will understand... but we don't have enough info in the question to provide any guidance yet in that area.
I fixed that for the purpose of using it in my program.
Now i can detect and understand such inputs:
"09 11 2008"
"2017"
"today"
"yesterday"
"09/11/2002"
"march 2017"
"01.01.2010"
"01-01-2010"
"01 may 2019"
"31.October 2020"
"01 april"
"december"
If anyone is also interested in writing a similar function leave a comment, because the code is almost 300 lines.
I use this C# code to convert a datetime to a string:
MyDatetime.ToString("dd/MM/yyyy HH:mm")
it works, but not every time. What do I mean?
If the input datetime is, for example, 2016-10-19 17:27:41.727, I get the string as expected, 19/10/2016 17:27. If the day in datetime (and/or the month) has only one digit, I get something weird.
If the input is 2016-01-07 14:58:13.560, I get 1/7/2016 and if it is 2016-10-26 17:14:16.000 I get 10/6/2016.
Do you know why? How can I always set a leading zero for days and months with only one digit? And, further, why I don't see the time part in the date I wrote as examples?
UPDATE
.
Some datetime fields from a SQL Server database (this is SQL Server Management Studio).
Most probably your DateTime already has invalid value (day and month are mixed)
new DateTime(2016, 01, 07,14,58,13,56).ToString("dd/MM/yyyy HH:mm")
returns 07-01-2016 14:58.
Take a look how do you read this DateTime value from the database. I believe the problem is there. (for example SqlDataReader.GetDateTime)
When you input a date as "XXXX-XX-XX" it assumes you're using the format "YYYY-MM-DD".
Just look at your input-output and you can see the pattern.
A lot of people in programming (that I work with) use this format because it is auto-filtering without any punctuation (20170102 will always go after 20161231, etc).
The DateTime method works in conjunction with the computer language. If your computer (or server) is in English (or vice versa) and you pass an American non-standard date format, you will have problems like this.
If you are using a web application, configure the correct language in web.config
I'm looking for a regular expression which matches the following datetime format:
dd-MMM-yyyy HH:mm:ss (15-Sep-2011 16:00:47)
Currently I only have the regex for date which looks something like this:
^(3[0-1]|2[0-9]|1[0-9]|0[1-9])[\s{1}|\/|-](Jan|JAN|Feb|FEB|Mar|MAR|Apr|APR|May|MAY|Jun|JUN|Jul|JUL|Aug|AUG|Sep|SEP|Oct|OCT|Nov|NOV|Dec|DEC)[\s{1}|\/|-]\d{4}$
Any ideas for the time part?
It's ok guys I found the solution. Submitting for anyone who wants to utilise it.
(3[0-1]|2[0-9]|1[0-9]|0[1-9])[\s{1}|\/|-](Jan|JAN|Feb|FEB|Mar|MAR|Apr|APR|May|MAY|Jun|JUN|Jul|JUL|Aug|AUG|Sep|SEP|Oct|OCT|Nov|NOV|Dec|DEC)[\s{1}|\/|-]\d{4}\s(20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d
Must it be a regex?
DateTime.TryParseExact will work much better.
DateTime myDate;
// dd-MMM-yyyy HH:mm:ss (15-Sep-2011 16:00:47)
if (DateTime.TryParseExact(dateAsString,
"dd-MMM-yyyy HH:mm:ss",
new CultureInfo("en-US"),
DateTimeStyles.None,
out myDate))
{ ... }
Err, it appears to me that the date bit is the hard one :-) But you can use the same methods for the time.
Assuming you have two fixed digits, you can use something like:
(([01][0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]
The first bit is the slightly tricky bit since you want one of:
0 or 1 followed by a digit.
2 followed by 0 thru 3.
The minutes and seconds are both:
0 thru 5 followed by 0 thru 9.
If you want to allow single-digit hours, just replace [01] with [01]?.
You may also want to consider the possibility that people may enter nov or OcT as the month, rendering your regex less useful.
This could be solved with a case-insensitive version which would also reduce the size of the regex as well, requiring only one string per month.
As Joel suggested above that I should add my solution as an answer here.
So here it is:
(3[0-1]|2[0-9]|1[0-9]|0[1-9])[\s{1}|\/|-](Jan|JAN|Feb|FEB|Mar|MAR|Apr|APR|May|MAY|Jun|JUN|Jul|JUL|Aug|AUG|Sep|SEP|Oct|OCT|Nov|NOV|Dec|DEC)[\s{1}|\/|-]\d{4}\s(20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d
Do let me know if it works out.
I'm using free-form dates as part of a search syntax. I need to parse dates from strings, but only preserve the parts of the date that are actually specified. For instance, "november 1, 2010" is a specific date, but "november 2010" is the range of dates "november 1, 2010" to "november 30, 2010".
Unfortunately, DateTime.Parse and friends parse these dates to the same DateTime:
DateTime.Parse("November 1, 2010") // == {11/1/2010 12:00:00 AM}
DateTime.Parse("November, 2010") // == {11/1/2010 12:00:00 AM}
I need to know which parts of the DateTime were actually parsed and which were guessed by the parser. Essentially, I need DateTime.Parse("November, 2010") == {11/-1/2010 -1:-1:-1}; I can then see that the day portion is missing and calculate the range of dates covering the whole month.
(Internally, C# has the DateTimeParse and DateTimeResult classes that parse the date and preserve exactly the information I need, but by the time the date gets back to the public interfaces it's been stripped off. I'd rather avoid reflecting into these classes, unless that's really the only route.)
Is there some way to get DateTime.Parse to tell me which format it used to parse the date? Or can the returned DateTime have placeholders for unspecified parts? I'm also open to using another date parser, but I'd like it to be as reliable and locale-flexible as the internal one. Thanks in advance.
EDIT: I've also tried ParseExact, but enumerating all of the formats that Parse can handle seems nearly impossible. Parse actually accepts more formats than are returned by DateTimeFormatInfo.GetAllDateTimePatterns, which is about as canonical a source as I can find.
You could try using TryParseExact(), which will fail if the data string isn't in the exact format specified. Try a bunch of different combinations, and when one succeeds you know the format the date was in, and thus you know the parts of the date that weren't there and for which the parser filled in defaults. The downside is you have to anticipate how the user will want to enter dates, so you can expect exactly that.
You could also use a Regex to digest the date string yourself. Again, you'll need different regexes (or a REALLY complex single one), but it is certainly possible to pull the string apart this way as well; then you know what you actually have.
Parse parses a whole lot of stuff that no sane person would enter as a date, like "January / 2010 - 21 12: 00 :2". I think you'll have to write your own date parser if you want to know what exactly the user entered.
Personally I would do it like KeithS suggested: Parse the string with Parse and only call your own parse function if there's a 0 in one of the fields of the DateTime object. There are not that that possibilities you need to check for, because if the day is 0, the time will be 0, too. So start checking year, month, day, etc..
Or simply instruct the user to use specific formats you recognize.
Essentially, I need
DateTime.Parse("November, 2010") ==
{11/-1/2010 -1:-1:-1}; I can then see
that the day portion is missing and
calculate the range of dates covering
the whole month.
What you want is an illegal DateTime because you cannot have a negative hours/seconds/minute/day values. If you want to return something else other then a legal DateTime you have to write your own method which does NOT return a DateTime.
Is there some way to get
DateTime.Parse to tell me which format
it used to parse the date? Or can the
returned DateTime have placeholders
for unspecified parts? I'm also open
to using another date parser, but I'd
like it to be as reliable and
locale-flexible as the internal one.
Take a look here http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx
You are going to have to manually keep track of what is entered to do this task. The only solution is to make sure the input is in the correct format.
I used this method that goes back to the original string in order to check for existence of the day and the year:
For days, the original string must contain a 1 as integer if the day was specified. So, split the string and look for a 1. The only exception occurs when the month is January (#1 month), so you should check for two 1s or a 1 and "January" or "Jan" in the original string.
For years, the original string must contain a number that can be a year (say, from 1900 to 2100). Other possibilities may be the use of an apostrophe, or things like 02-10-16, which you can recognize by the fact that there are exactly three numbers.
I know that this is pretty heuristic, but it's a fast and simple solution that works in most cases. I coded this algorithm in C# in the DateFinder.DayExists() and DateFinder.YearExists() methods in the sharp-datefinder library.
Working on an application where we would like the user to be able to enter incomplete dates.
In some cases there will only be a year - say 1854, or there might be a year and a month, for example March 1983, or there may be a complete date - 11 June 2001.
We'd like a single 'date' attribute/column - and to be able to sort on date.
Any suggestions?
Store the date as an integer -- yyyymmdd.
You can then zero out any month or day component that has not been entered
Year only: 1954 => 19540000
Year & Month: April 2004 => 20040400
January 1st, 2011 => 20110101
Of course I am assuming that you do not need to store any time of day information.
You could then create a struct to encapsulate this logic with useful properties indicating which level of granularity has been set, the relevant System.DateTime, etc
Edit: sorting should then work nicely as well
I can't think of a good way of using a single date field.
A problem you would get if you used January as the default month and 1 as the default day like others have suggested is, what happens when they actually pick January? How would you track if it's a selected January or a defaulted January.
I think you're going to have to store a mask along with the date.
You would only need a bit per part of the date, which would only be 6 bits of data.
M|D|Y|H|Min|S
Month Only 1|0|0|0|0|0 = 32
Year Only 0|0|1|0|0|0 = 8
Month+Year 1|0|1|0|0|0 = 40
AllButMinSec 1|1|1|1|0|0 = 60
You could put this into a Flag Enum to make it easier to use in code.
Well, you could do it via a single column and field that says 'IsDateComplete'.
If you only have the date field, then you'll need to encode the "incompleteness" in the date format itself, such that if the date is, say, < 1900, it's considered "Incomplete".
Personally, I'd go with an field on the side, that marks it as such. Easier to follow, easier to make decisions on, and allows for any dates.
It goes without saying, perhaps, that you can just create a date from DateTime.MinValue and then set what you "know".
Of course, my approach doesn't allow you to "know" what you don't know. (That is, you don't know that they've set the month). You could perhaps use a date-format specifier to mask that, and store it alongside as well, but it's potentially getting cumbersome.
Anyway, some thoughts for you.
One option is to use January as the default month, 1 as the default day, and 1900 or something like that as the default year. Incomplete dates would get padded out with those defaults, and incomplete dates would sort before complete ones in the same year.
Another, slightly more complex option is to use -1 for default day and year, and -1, 'NoMonth', or some such as the default month. Pad incomplete dates as above. This may make sorting a little hard depending on how you do it, but it gives you a way of telling which parts of the date are valid.
I know you'd rather have 1 column but, Instead of a single column one can always have a separate column for day, month and year. Not very difficult to do queries against, and it allways any of the components to be null.
Smehow encoding these states in the datetime itself will be harder to query.
What I did when last solving this problem, was to create a custom date type that kept track of which date parts was actually set and provided conversions to and from a DateTime. For storing in database i used one date field and then one boolean/bit to keep track of which date components that were actually set by the user.