I have some automated C# windows services to upload text to the database. The 'text' is generated by a third party application where we don't have any control.
My issue is that the text contains a column for date.
The default date format is DD/MM/YY. But some times we get MM/YY/DD
Is there any tricky way to identify or convert MM/YY/DD to DD/MM/YY. The data might only contain date for three, four days. So I plan to check if the date is in tolerance with three or four days, it will be accepted. Other wise manually correct it.
For example,
14/08/17 is accepted
08/17/14 is not accepted. Logic should convert this to 14/08/17
Any ideas ?
You could try and parse with the good format, if it goes ok there is no problem, it will return the date. If it goes wrong, you tryparse with the 'secondary format'. If everything goes ok, it will return the date.
Note that if the parsed date it's more than 3 days ahead, it won't count as a valid date and will return null.
if(DateTime.TryParseExact(input, "dd/MM/yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateValue)
{
int daysBetween = (dateValue-DateTime.Now).Days
if(daysBetween < 4)
{
return dateValue
}
}
if(DateTime.TryParseExact(input, "MM/yy/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateValue)
{
int daysBetween = (dateValue-DateTime.Now).Days
if(daysBetween < 4)
{
return dateValue;
}
}
return null
If null gets returned, you'll have an invalid date, if not, that will be the parsed date
Related
I have to parse date string in C#. The dates are all ensured to start with year, month, day. But I do not know what dividers will be between the 3 parts.
Additionally the date string may also include a time part after the date.
Basically as long as the format has the year first, month second, and day third, I should parse it as a valid date regardless of which dividers are used and whether a time is included. Any other date formats should be rejected as invalid.
I can not figure out how to do this without writing a long if/else.
How do I parse a string into a C# datetime object, given the restrictions mentioned?
You can check the length of the input string is at least 10 characters, and if it is, work out what the separator should be by looking at the 5th character in the string.
Then you can use the separator to construct a format string that you pass to DateTime.TryParseExact() to parse the date. You also have to truncate the date string to 10 characters to ignore any date part at the end.
An example implementation looks like this - it returns null if the date didn't parse; otherwise, it returns the correctly parsed date:
public static DateTime? ParseDateWithUnknownDivider(string dateStr)
{
if (dateStr.Length < 10)
return null;
char divider = dateStr[4];
if (DateTime.TryParseExact(
dateStr.Substring(0, 10),
$"yyyy\\{divider}MM\\{divider}dd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out DateTime result))
return result;
return null;
}
Note that this ignores the time part and will always return the time part as 00:00:00. If that's not what you meant, you will need to specify in your question what the time part would look like. For example, would it be separated from the date part by a space? And would it always be hh:mm:ss? And would it be 24hour clock?
try this code
string yourDateTimeString = ....;
string format="yyyy/MM/dd";
var dt = DateTime.ParseExact(yourDateTimeString,format,null,System.Globalization.DateTimeStyles.AssumeLocal);
I have three textboxes named borrower_date_txt,period_txt and ret_date_txt.
Now, I want to make calculation on those textboxes. I want to enter the date into the borrower_date_txt (not only today's date), and in the period_txt I enter a period for example 5. In the ret_date_txt I want to display the
borrower_date_txt + 5
i.e give me the date after 5 days of borrower_date_txt date value in the ret_date_txt?
DateTime borrowerDate;
if (DateTime.TryParse(borrower_date_txt.Text, out borrowerDate))
{
int days;
if (int.TryParse(period_txt.Text, out days))
{
var retDate = borrowerDate.AddDays(days);
ret_date_txt.Text = retDate.ToShortDateString();
}
}
The important parts of the above code are as follows:
DateTime.TryParse(...): this will return false if the text isn't a valid date; otherwise it will assign the DateTime value to the borrowerDate. This is a way of safe-guarding your code. Parsing dates can get much more complex quickly, but I'm thinking this will likely due for your situation.
int.TryParse(...): this will return false if the text isn't a valid integer; otherwise it will assign the int value to the days. This is a way of safe-guarding your code.
borrowerDate.AddDays(days): this actually adds the days entered to the date entered.
ret_date_txt.Text = retDate.ToShortDateString(): this displays the result in the ret_date_txt text box, and formats it as a short date (i.e. without the time).
Basically, you can use the DateTime.AddDays method in order to increase a DateTime:
try
{
DateTime date = DateTime.Parse(borrower_date_txt.Text);
int period = Int32.Parse(period_txt.Text);
ret_date_txt.Text = date.AddDays(period).ToShortDateString();
}
catch(Exception ex)
{
//Handle parsing errors maybe
}
First you need to parse your text boxes values to proper date time objects:
DateTime Date1= DateTime.ParseExact(TextBox1.Text, "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture)
Then you can perform all the relevant DateTime operations on Date1.
I don't want to validate txtBirthDate so I want to pass DateTime.MinValue in database.
My code:
if (txtBirthDate.Text == string.Empty)
objinfo.BirthDate = DateTime.MinValue;
else
objinfo.BirthDate = DateTime.Parse(txtBirthDate.Text);
DateTime.MinValue return Date = {1/1/0001 12:00:00 AM}
I got a SQL Error:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
I under stand it but I don't understand why DateTime.MinValue return invalid date time which is unable to insert in database.How to handle this type of situation?
Very simple avoid using DateTime.MinValue use System.Data.SqlTypes.SqlDateTime.MinValue instead.
Basically, don't use DateTime.MinValue to represent a missing value. You can't use DateTime.MinValue in a SQL Server DateTime field, as SQL Server has a minimum value of the start of 1753.
Instead, make your BirthDate property a Nullable<DateTime> (aka DateTime?), and set it to null when you don't have a value. Also make sure your database field is nullable. Then you just need to make sure that that null ends up as a NULL value in the database. Exactly how you do that will depend on your data access, which you haven't told us anything about.
Well... its quite simple to get a SQL min date
DateTime sqlMinDateAsNetDateTime = System.Data.SqlTypes.SqlDateTime.MinValue.Value;
Although it is an old question, another solution is to use datetime2 for the database column.
MSDN Link
Here is what you can do. Though there are lot many ways to achieve it.
DateTime? d = null;
if (txtBirthDate.Text == string.Empty)
objinfo.BirthDate = d;
else
objinfo.BirthDate = DateTime.Parse(txtBirthDate.Text);
Note: This will work only if your database datetime column is Allow Null. Else you can define a standard minimum value for DateTime d.
I am using this function to tryparse
public static bool TryParseSqlDateTime(string someval, DateTimeFormatInfo dateTimeFormats, out DateTime tryDate)
{
bool valid = false;
tryDate = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
System.Data.SqlTypes.SqlDateTime sdt;
if (DateTime.TryParse(someval, dateTimeFormats, DateTimeStyles.None, out tryDate))
{
try
{
sdt = new System.Data.SqlTypes.SqlDateTime(tryDate);
valid = true;
}
catch (System.Data.SqlTypes.SqlTypeException ex)
{
}
}
return valid;
}
From MSDN:
Date and time data from January 1, 1753, to December 31, 9999, with an
accuracy of one three-hundredth second, or 3.33 milliseconds. Values
are rounded to increments of .000, .003, or .007 milliseconds. Stored
as two 4-byte integers. The first 4 bytes store the number of days
before or after the base date, January 1, 1900. The base date is the
system's reference date. Values for datetime earlier than January 1,
1753, are not permitted. The other 4 bytes store the time of day
represented as the number of milliseconds after midnight. Seconds have
a valid range of 0–59.
SQL uses a different system than C# for DateTime values.
You can use your MinValue as a sentinel value - and if it is MinValue - pass null into your object (and store the date as nullable in the DB).
if(date == dateTime.Minvalue)
objinfo.BirthDate = null;
Simply put, don't use DateTime.MinVaue as a default value.
There are a couple of different MinValues out there, depending which environment you are in.
I once had a project, where I was implementing a Windows CE project, I was using the Framework's DateTime.MinValue (year 0001), the database MinValue (1753) and a UI control DateTimePicker (i think it was 1970). So there were at least 3 different MinValues that were leading to strange behavior and unexpected results. (And I believe that there was even a fourth (!) version, I just do not recall where it came from.).
Use a nullable database field and change your value into a Nullable<DateTime> instead. Where there is no valid value in your code, there should not be a value in the database as well. :-)
If you use DATETIME2 you may find you have to pass the parameter in specifically as DATETIME2, otherwise it may helpfully convert it to DATETIME and have the same issue.
command.Parameters.Add("#FirstRegistration",SqlDbType.DateTime2).Value = installation.FirstRegistration;
use extensions
public static class DateTimeExtensions
{
public static DateTime MinValue(this DateTime sqlDateTime)
{
return new DateTime(1900, 01, 01, 00, 00, 00);
}
}
DateTime date = DateTime.Now;
Console.WriteLine("Minvalue is {0} ", date.MinValue().ToShortDateString());
I am suppose to let the user enter a DateTime format, but I need to validate it to check if it is acceptable. The user might enter "yyyy-MM-dd" and it would be fine, but they can also enter "MM/yyyyMM/ddd" or any other combination. Is there a way to validate this?
Are you looking for something like this?
DateTime expectedDate;
if (!DateTime.TryParse("07/27/2012", out expectedDate))
{
Console.Write("Luke I am not your datetime.... NOOO!!!!!!!!!!!!!!");
}
If your user knows the exact format(s) needed...
string[] formats = { "MM/dd/yyyy", "M/d/yyyy", "M/dd/yyyy", "MM/d/yyyy" };
DateTime expectedDate;
if (!DateTime.TryParseExact("07/27/2012", formats, new CultureInfo("en-US"),
DateTimeStyles.None, out expectedDate))
{
Console.Write("Thank you Mario, but the DateTime is in another format.");
}
I don't know of any way to actually validate the format they enter since sometimes you want to intentionally include characters that translate into anything. One thing you might consider is allowing the user to self validate by showing a preview of what their entered format translates into.
I assume you want to know if the specified format string is valid...
For this you could round-trip it:
private bool IsValidDateFormat(string dateFormat)
{
try
{
String dts=DateTime.Now.ToString(dateFormat, CultureInfo.InvariantCulture);
DateTime.ParseExact(dts, dateFormat, CultureInfo.InvariantCulture);
return true;
}
catch (Exception)
{
return false;
}
}
Unless I am remembering incorrectly, the only invalid DateTime format strings are one character long. You can assume any 2 or more character DateTime format string is valid.
DateTime.ParseExact("qq", "qq", null) == DateTime.Today
DateTime.ParseExact("myy", "501", null) == "05/01/2001"
Standard (1 character)
Custom (>1 character)
For reference, allowed single character strings as formats:
d,D,f,F,g,G,m,M,o,O,r,R,s,T,u,U,y,Y
Any other character, such as q, by itself is invalid. All other strings will be successfully parsed as formatting strings.
You don't talk about your validation strategy. Anyway you should use something involving regular expressions and than apply allowed patterns. This would help against the formal validity .. then you have to take care about the actual contents and be sure the values are correct according as month, day and year.
Anyway several people suggested to use the DateTime.TryParse() method to let the substrate take care for you. But you'll have to specify the format anyway! so there's no magic! you would fall in ambiguity otherwise
This works for me-
try
{
String formattedDate = DateTime.Now.ToString(dateFormat);
DateTime.Parse(formattedDate);
return true;
}
catch (Exception)
{
return false;
}
static private bool IsValidDateFormat(string dateFormat)
{
try
{
DateTime pastDate = DateTime.Now.Date.Subtract(new TimeSpan(10, 0, 0, 0, 0));
string pastDateString = pastDate.ToString(dateFormat, CultureInfo.InvariantCulture);
DateTime parsedDate = DateTime.ParseExact(pastDateString, dateFormat, CultureInfo.InvariantCulture);
if (parsedDate.Date.CompareTo(pastDate.Date) ==0)
{
return true;
}
return false;
}
catch
{
return false;
}
}
I do use this code - it is a modification of shapiro yaacov posting.
It looks as "DateTime.ParseExact" does not throw an exception when using an invalid dateformat string - it just returns "DateTime.Now".
My approach is to convert a date in the past to string and then check if this is returned by ParseExact()
The answer by ZipXap accepts any format that doesn't throw an exception, yet something like "aaaa" will pass that validation and give the current date at midnight ("26-Apr-22 00:00:00" when writing this).
A better aproach is to use the DateTimeStyles.NoCurrentDateDefault option and compare the result to default:
using System.Globalization;
var format = "aaaaa";
try {
var dt = DateTime.ParseExact(
DateTime.Now.ToString(format, CultureInfo.InvariantCulture),
format,
CultureInfo.InvariantCulture,
DateTimeStyles.NoCurrentDateDefault);
return dt != default;
} catch {
return false;
}
/*
"aaaaa" -> false
"h" -> false
"hh" -> true
"fff" -> true
"gg" -> false
"yyyy gg" -> true
"'timezone: 'K" -> false
"zzz" -> false
*/
My solution was to mark the input-field as read-only and allow users to change the value only by jqueryui datepicker.
It is intuitive. You can specify your preferred format and need only to validate this one format.
Otherwise you may get really in trouble. What are you going to do with "02/03/2020" in USA you interpret it as the third of February, but for south america it is definitely the second of March. And there are a lot of other Date formats around the globe.
I have an internal business process that my finance dept runs. To kick it off they input a Date in the format of yyyyMM or 201009. I want to check for a valid date from that string but so far I got nothing.
I am currently exploring breaking the string up, taking the first 4 and checking that they are between 1990 and 2050(as example) and then the last 2 and checking that it is between 01 and 12.
Is there a better way?
You can use DateTime.TryParseExact to see if it can be parsed correctly:
bool isValid = false;
DateTime dateValue;
if(DateTime.TryParseExact("201009", "yyyyMM", CultureInfo.InvariantCulture,
DateTimeStyles.None, out dateValue))
{
// DateTime parsed, dateValue contains the parsed DateTime
// Can validate dateValue against business rules at this point
isValid = (dateValue <= DateTime.Now && dateValue >= DateTime.Now.AddYears(-5));
}
If you would rather get an exception, you can use DateTime.ParseExact:
// Next line throws exception if format not correct
DateTime.ParseExact("201009", "yyyyMM", CultureInfo.InvariantCulture);
You can use a regular expression:
if (Regex.IsMatch(input, #"^(199\d|20[0-5]\d)(0[1-9]|1[0-2])$")) {
// valid input between 199001 and 205912
}
I would go with DateTime.ParseExact:
DateTime d = DateTime.ParseExact("201009", "yyyyMM", System.Globalization.CultureInfo.InvariantCulture);
The problem here is that the format "yyyyMM" cannot represent a specific DateTime. So the parsing methods built in to DateTime will do you no good.
Update: Never mind; I stand corrected. DateTime.TryParseExact will work just fine (which is ironic, if you ask me); it'll interpret your string to represent the first day of the given month.
I would do what you're describing: parsing the string into the two numeric components and simply compare those values to whatever range you require them to fall within.
I'd be tempted perform this as a number range problem:
UInt32 val;
if (input.Length != 6
|| !UInt32.TryParse(input, out val)
|| val > 205012
|| val < 199001
|| val % 100 > 12
|| val % 100 == 0) {
// Invalid...
}