Use DateTime.TryParseExact to format date string and ignore time - c#

I want to parse string date to DateTime but ignoring time.
My expected date format is M/d/yyyy which is 3/29/2018 (without leading zero).
The thing is string can be with or without time part and time can have different formats that I will not predict.
var inputDateString = "12/31/2017 12:00:00 AM" // false, but I want to parse
var inputDateString = "12/31/2017" // true
DateTime.TryParseExact(inputDateString, "M/d/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate);
Is there any way to parse date string having only specific date format and ignore time?

There is an overload to TryParseExact that allows you to pass in multiple formats. If you know in advance which formats to expect, you can use this overload:
void Main()
{
string[] validFormats = {"M/d/yyyy", "M/d/yyyy hh:mm:ss tt"};
var inputDateString1 = "12/31/2017 12:00:00 AM"; // false, but I want to parse
var inputDateString2 = "12/31/2017"; // true
DateTime.TryParseExact(inputDateString1, validFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt1);
DateTime.TryParseExact(inputDateString2, validFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt2);
}
You can then get only the date portion using the Date property.

You could strip the time part from the input string, or parse the full input, using only the .Datepart.
var parsedDate = DateTime.MinValue;
var inputDateString = "12/31/2017 12:00:00 AM"; // false, but I want to parse
// option 1: use only the date part
if (DateTime.TryParseExact((inputDateString ?? "").Split(' ')[0] , "M/d/yyyy",
CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate))
Console.WriteLine(parsedDate);
// option 2: use the full input, but ignore the time
if (DateTime.TryParseExact(inputDateString, "M/d/yyyy hh:mm:ss tt",
CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate))
Console.WriteLine(parsedDate.Date);
Personally, I would go with the first option.

If you always want to only parse the Date portion that can be done by explicitly ensuring the string is only 10 characters in length. This is a somewhat convoluted example but you can strip out what you don't need, you'll get the idea:
var inputDateString = "12/31/2017 12:00:00 AM";
string datePortion = string.Empty;
DateTime dt;
if (inputDateString.Length>10)
{
// take first 10 characters of inputDateString
datePortion = inputDateString.Substring(0, Math.Min(inputDateString.Length, 10));
}
else if (inputDateString.Length==10)
{
// inputDateString is already 10 characters
datePortion = inputDateString;
}
else
{
// inputDateString is less than 10 characters, no date found, do nothing.
}
if(!DateTime.TryParse(datePortion, out dt))
{
// handle error that occurred,
}
else
{
// parse was successful, carry on.
}

Related

DateTime.TryParseExact Parses date value but adds default time value (where there was none)

edit: since I've had so many comments regarding utilising TryParseExact with a single format instead of an array:
I must test all of the formats within the array - the inputs can potentially be these formats, and my unit tests for these other formats actually work. I MUST use them all.
I am aware that DateTime.TryParse would match the first and not iterate further. Hence I am using TryParseExact as Microsoft shows. It should match exactly. BUT it doesn't work in this scenario.
TLDR: Given a string of the format "dd/MM/yyyy" with value "29/11/2019" DateTime.TryParseExact returns a match with the format "dd/MM/yyyy hh:mm tt" and value 29/11/2019 12:00 AM. Why?
Question: How can I ensure a string of the format "dd/MM/yyyy" returns as a match with the format "dd/MM/yyyy" instead of "dd/MM/yyyy hh:mm tt" when using TryParseExact?
The long explanation of Context;
I have the following problem. I need to parse multiple date formats from strings to datetime values. They (input strings) can appear in the following formats:
{ "dd/MM/yyyy hh:mm tt", "dd/M/yyyy hh:mm tt", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:m", "dd/MM/yyyy", "dd-MM-yyyy", "d-M-yyyy", "dddd, d MMMM yyyy"};
To solve this, I wrote a string extension that parses a given input string and returns a bool success and a potential matching format.
private static readonly string[] _DateFormats = new string[] { "dd/MM/yyyy hh:mm tt", "dd/M/yyyy hh:mm tt", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:mm", "dd/MM/yyyy H:m", "dd/MM/yyyy", "dd-MM-yyyy", "d-M-yyyy", "dddd, d MMMM yyyy"};
public static bool StringToDateTime(this string dateTimeString, out DateTime dateTimeValue, out string matchingFormat)
{
matchingFormat = ""; // defaults
dateTimeValue = new DateTime();
if (string.IsNullOrEmpty(dateTimeString)) return false;
foreach (string format in DateFormats)
{
matchingFormat = format;
if (DateTime.TryParseExact(dateTimeString, DateFormats, AUSCulture, DateTimeStyle, out dateTimeValue)) return true;
}
return false;
}
This returns the string input "29/11/2019 successfully" as the DateTime 29/11/2019 12:00 AM with the matching format as "dd/MM/yyyy hh:mm tt", rather than the format matching the original input 29/11/2019.
Given this issue, the only (duct-tape) solution I could think of is:
public static bool StringToDateTime(this string dateTimeString, out DateTime dateTimeValue, out string matchingFormat)
{
matchingFormat = ""; // defaults
dateTimeValue = new DateTime();
if (string.IsNullOrEmpty(dateTimeString)) return false;
foreach (string format in DateFormats)
{
matchingFormat = format;
if (DateTime.TryParseExact(dateTimeString, DateFormats, AUSCulture, DateTimeStyle, out dateTimeValue))
{
// ensure the datetime format is consistent with the dateTimeString passed to us.
if(dateTimeString.Length != matchingFormat.Length)
{
var _matchingFormat = DateFormats.First(d => d.Length == dateTimeString.Length);
matchingFormat = string.IsNullOrEmpty(_matchingFormat) ? matchingFormat : _matchingFormat;
}
return true;
}
}
return false;
}
Which works, but obviously, this has further issues (begetting the formatting of input, etc.). So I'd rather not use this.
System.DateTime cannot exist without the time component, so it's no possible to parse a date to DateTime and not the time component. It will default to the start of day e.g. 12:00 AM, which is the same result as calling dateTime.Date(). This will allow you to compare two dates without considering the time of day.
If having or storing the time element really bothers you then you can either create your own struct to store the date or consider using something like NodaTime that provides a date only struct.
Also, Dotnet 6 will introduce DateOnly and TimeOnly structs to do exactly this. You can read more about it on the MS devblogs.
You are passing the whole array of formats, so it will match any of them.
Since you are in a foreach over DateFormats, you only need to match against the current value.
So replace this line
if (DateTime.TryParseExact(dateTimeString, DateFormats, AUSCulture, DateTimeStyle, out dateTimeValue))
return true;
with this
if (DateTime.TryParseExact(dateTimeString, format, AUSCulture, DateTimeStyle, out dateTimeValue))
return true;

Error “String was not recognized as a valid DateTime” [duplicate]

This question already has answers here:
unable to parse a string of this format "1/29/2020 12:00:00 AM" into a valid DateTime
(2 answers)
Closed 2 years ago.
I have these 2 string values:
Test1 = "2020-01-29T00:00:00Z"
Test2 = "29/01/2020 00:00:00"
and I am doing this comparison:
(DateTime.ParseExact(Test2.ToString(), "dd/M/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture).ToString("yyyy'-'MM'-'dd'T'00':'00':'00'Z'") != (DateTime.ParseExact(Test1["ProjectDateSinged"].ToString(), "yyyy'-'MM'-'dd'T'00':'00':'00'Z'", CultureInfo.InvariantCulture)).ToString()))
but this will raise the following exception:
Error “String was not recognized as a valid DateTime”
Could anyone find what is wrong with my code?
Expanding my comment into answer, you should update your format string a little bit. For Test2 you should use dd/MM/yyyy hh:mm:ss format.
According to Custom date and time format strings MM is used for month number from 01 to 12, M from 1 to 12. You have 01 month number, so MM should be used.
There is also no AM/PM representation in your date, so tt is not needed as well
Them you'll be able to parse Test2 into the date.
var Test2 = "29/01/2020 00:00:00";
var result = DateTime.ParseExact(Test2, "dd/MM/yyyy hh:mm:ss", CultureInfo.InvariantCulture);
For the Test1 you can use yyyy-MM-ddThh:mm:ssK (parse the date including time zone information) or yyyy-MM-ddThh:mm:ss'Z' without time zone information.
To compare the dates you don't need to convert them back to string. You can simply get the date component using Date property of DateTime struct. The code below returns true
var result = DateTime.ParseExact(Test1, "yyyy-MM-ddThh:mm:ss'Z'", CultureInfo.InvariantCulture).Date ==
DateTime.ParseExact(Test2, "dd/MM/yyyy hh:mm:ss", CultureInfo.InvariantCulture).Date;
as well as this, by comparing two DateTime instances only
var result = DateTime.ParseExact(Test1, "yyyy-MM-ddThh:mm:ss'Z'", CultureInfo.InvariantCulture) ==
DateTime.ParseExact(Test2, "dd/MM/yyyy hh:mm:ss", CultureInfo.InvariantCulture);
string Test1 = "2020-01-29T00:00:00Z";
string Test2 = "29/01/2020 00:00:00";
DateTime dt = Convert.ToDateTime(Test1, CultureInfo.InvariantCulture);
MessageBox.Show("" + dt.ToString("yyyy-MM-ddT00:00:00Z"));
Used this code then successfully work
By looking at your examples, the formats looks below.. You can write a generalized method by specifying formats. something like below -
private static DateTime ParseDate(string providedDate)
{
DateTime validDate;
string[] formats = { "dd/MM/yyyy hh:mm:ss", "yyyy-MM-dd'T'hh:mm:ss'Z'" };
var dateFormatIsValid = DateTime.TryParseExact(
providedDate,
formats,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out validDate);
return dateFormatIsValid ? validDate : DateTime.MinValue;
}
And call this method to parse the string
var test1 = ParseDate("2020-01-29T00:00:00Z");
var test2 = ParseDate("29/01/2020 00:00:00");
Console.WriteLine(test1 == test2); // result TRUE

date to be converted to UK date format with preserving 0's

I want my date to be converted to UK date format.
so example if its 26/2/2016 then it should be converted to 26/02/2016.
if its a 2/13/2016 then it should be converted to 13/02/2016.
The end result should be UK format with preserving 0 in day and month.
Code
string cellvalue;
string oData = "2/13/2016";
if (DateTime.TryParse((string)oData, CultureInfo.CurrentUICulture, styles, out dt))
{
cellvalue = dt.ToString("dd/MM/yyyy");
Console.WriteLine(cellvalue + "go to hell");
}
else
{
cellvalue = oData.ToString();
Console.WriteLine(cellvalue + "go to bokaro");
}
Easyyy:
CultureInfo enGB = new CultureInfo("en-GB");
string oData = "2/13/2016";
DateTime dateValue;
// Parse date with no style flags.
dateString = "13/02/2016";
DateTime.TryParseExact(oData, "g", enGB, DateTimeStyles.None, out dateValue);
As far as I understand you want resulting date to be in default UK format i.e. dd/MM/yyyy no matter if input date string is in MM/dd/yyyy or dd/MM/yyyy, former being default format for US dates.
You were close in the code you have already tried. Additionally you need to one thing - if input is in US format, parse it as DateTime using US culture, and then simply transform to UK.
var UKCulture = new CultureInfo("en-GB");
var USCulture = new CultureInfo("en-US");
DateTime dt;
string cellvalue;
string oData = "13/2/2016";
// First try parsing to UK format
if (!DateTime.TryParse(oData, UKCulture, DateTimeStyles.None, out dt))
{
// If fails, then try US format
DateTime.TryParse(oData, USCulture, DateTimeStyles.None, out dt);
}
// Once you have DateTime instance, you can do anything. Parsing is over.
cellvalue = dt.ToString("dd/MM/yyyy");
Console.Write(cellvalue);
So now this gives final value as 13/02/2016 for both 2/13/2016 and 13/2/2016 inputs.

How to parse date with minutes contains value 60?

I am getting exception when the minute contains value 60
var date = "30/10/14 08:60";
var result = DateTime.ParseExact(date, "dd/MM/yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None);
How do i parse it correctly??
Either pass a correct value(>=0 || <=59) or use this:
var date = "30/10/14 08:60";
DateTime dateResult;
bool canParse = DateTime.TryParseExact(date, "dd/MM/yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateResult);
if (!canParse)
{
string datePart = date.Split().First();
DateTime dtOnly;
if (DateTime.TryParseExact(datePart, "dd/MM/yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dtOnly))
{
string timePart = date.Split().Last();
string hourPart = timePart.Split(':')[0];
string minutePart = timePart.Split(':').Last();
int hour, minute;
if (int.TryParse(hourPart, out hour) && int.TryParse(minutePart, out minute))
{
TimeSpan timeOfDay = TimeSpan.FromHours(hour) + TimeSpan.FromMinutes(minute);
dateResult = dtOnly + timeOfDay; // 10/30/2014 09:00:00
}
}
}
First of all, the data is invalid, and this is why an exception is raised.
So, basically there are 2 resolutions:
If the data is from the 3rd party, my suggestion is that after consulting with your boss or company's lawyers you/your company asks the 3rd party to provide valid data, since you don't have legal obligation to fix/tolerate the invalid data for the 3rd party. IMO, you shouldn't.
If the data is from your legacy internal systems, you/company should fix the bugs that may produce 60. If for some reasons the bugs can't be fixed shortly, you may write a parser for example using regular expression to parse the data and tolerate 60.
So the 2nd resolution with regular expression is to answer your question directly. However, please be mindful that "30/10/14 08:60" is invalid, and must be fixed sooner or later in the data source.
BTW, here's the link with some regular expressions you may try.
For international convention are 60 minutes in an hour.
The sixtieth minute would be 59, in fact if you count from 0 to 59 find that they are 60 numbers. The date you write 8:60 does not exist, the value of them is 9:00.
Try this(Obviously only date1 raises an exception):
var date = "30/10/14 8:59";
var date1 = "30/10/14 9:00";
var result = DateTime.ParseExact(date, "dd/MM/yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None);
var result1 = DateTime.ParseExact(date1, "dd/MM/yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None);
In addition at this you can use this for controlling a data and receiving a message true/false
var date = "30/10/14 08:60";
DateTime outData;
Boolean flagCorrectData = DateTime.TryParseExact(date, "dd/MM/yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out outData);
if (flagCorrectData)
{
MessageBox.Show("Date correct");
}
else
{
MessageBox.Show("Date error");
}
If you always know if the time portion of your date string is of the format HH:mm, you can do this to get the right DateTime date:
string dateString = "30/10/14 08:60";
string[] dateParts = dateString.Split(' ');
DateTime date = DateTime.ParseExact(dateParts[0],"dd/MM/yy",CultureInfo.InvariantCulture);
string[] timeParts = dateParts[1].Split(':');
date=date.AddMinutes(double.Parse(timeParts[0])*60+double.Parse(timeParts[1]));
If you only care precisely about the special case of :60, you can use 60 in ParseExact explicitly:
string date = "30/10/14 08:60";
DateTime result;
if(DateTime.TryParseExact(date, "dd/MM/yy HH:mm",
CultureInfo.InvariantCulture, DateTimeStyles.None,out result))
{
return result;
}
//Handle weird :60
if(DateTime.TryParseExact(date, "dd/MM/yy HH:60",
CultureInfo.InvariantCulture, DateTimeStyles.None,out result))
{
return result.AddMinutes(60);
}
throw new ArgumentException("date");

I am getting Error as String was not recognized as a valid DateTime

private string format = "dd/MM/yyyy HH:mm:ss";
DateTime fromdate = DateTime.ParseExact(GetFromScanDateTextBox.Text, format, CultureInfo.InvariantCulture);
I am getting error when executing this line string was not recognized as a Valid Date Time.
I have tried this also but it not works
DateTime fromdate = DateTime.ParseExact(GetFromScanDateTextBox.Text, format,null);
Your format string must be "d/M/yyyy", take a look at this.
Basically
MM : The month, from 01 through 12.
while
M : The month, from 1 through 12.
The same for the day part.
You are telling DateTime.ParseExact that you are expecting a string with format dd/MM/yyyy HH:mm:ss but you are giving it a string with format d/M/yyyy.
You need to change your format to just d/M/yyyy.
Also I suggest using DateTime.TryParseExact to verify the validity of your string instead of using exceptions.
var okay = DateTime.TryParseExact(
input,
new[] { "dd/MM/yyyy HH:mm:ss", "d/M/yyyy" },
new CultureInfo("en-GB"),
DateTimeStyles.None,
out dateTime);
If your input string is liable to change, TryParseExact allows you to define multiple formats as shown above, or alternatively, if it is always going to be with your current culture, just do DateTime.TryParse and do away with defining the format.
var okay = DateTime.TryParse(input, out dateTime);
If your format is always month/date/year and particularly in this case(if your date is 3rd Sept 2013) you can use:
string format = "MM/dd/yyyy";
string dateTime = "9/3/2013";
dateTime = (dateTime.Split('/')[0].Length == 1 ? "0" + dateTime.Split('/')[0] : dateTime.Split('/')[0]) + "/" + (dateTime.Split('/')[1].Length == 1 ? "0" + dateTime.Split('/')[1] : dateTime.Split('/')[1]) + "/" + dateTime.Split('/')[2];
DateTime fromdate = DateTime.ParseExact(dateTime, format, CultureInfo.InvariantCulture);
Do not provide the HH:MM:SS part in the format part
string format = "dd/MM/yyyy";
DateTime fromdate = DateTime.ParseExact(test.Text, format, CultureInfo.InvariantCulture);

Categories

Resources