I'm testing a piece of code to see if the rules will work each time, so I just made a short console application that has 1 string as an input value which I can replace at any time.
string titleID = "document for the period ended 31 March 2014";
// the other variation in the input will be "document for the period
// ended March 31 2014"
What I'm doing is I take a specific part from it (depending if it contains a specific word - nvm the details, there is a consistency so I don't worry about this condition). Afterwards I'm taking the rest of the string after a specific position in order to do a DateTime.ParseExact
Ultimately I need to figure out how to check if the first DateTime.ParseExact has failed
to then perform a second attempt with a different custom format.
This is how it looks like:
if(titleID.Contains("ended "))
{
// take the fragment of the input string after the word "ended"
TakeEndPeriod = titleID.Substring(titleID.LastIndexOf("ended "));
// get everything after the 6th char -> should be "31 March 2014"
GetEndPeriod = TakeEndPeriod.Substring(6);
format2 = "dd MMMM yyyy"; // custom date format which is mirroring
// the date from the input string
// parse the date in order to convert it to the required output format
try
{
DateTime ModEndPeriod = DateTime.ParseExact(GetEndPeriod, format2, System.Globalization.CultureInfo.InvariantCulture);
NewEndPeriod = ModEndPeriod.ToString("yyyy-MM-ddT00:00:00Z");
// required target output format of the date
// and it also needs to be a string
}
catch
{
}
}
// show output step by step
Console.WriteLine(TakeEndPeriod);
Console.ReadLine();
Console.WriteLine(GetEndPeriod);
Console.ReadLine();
Console.WriteLine(NewEndPeriod);
Console.ReadLine();
Everything works fine until I try a different input string, f.eg. "document for the period ended March 31 2014"
So in this case if wanted to parse "March 31 2014" I'd have to switch my custom format to
"MMMM dd yyyy" and I do that and it works, but I cannot figure out how to check if the first parse fails in order to perform the second one.
First parse - > success -> change format and .ToString
|-> check if failed , if true do second parse with different format -> change format and .ToString
I've tried
if (String.IsNullOrEmpty(NewEndPeriod))
{ do second parse }
Or
if (NewEndPeriod == null)
{ do second parse }
But I get a blank result at Console.WriteLine(NewEndPeriod);
Any ideas how to approach this?
** EDIT: **
Adding here an alternative answer I got which is using Parse instead of TryParseExact, since Parse will handle both of the format variations without the need to specify them
DateTime DT = DateTime.Parse(GetEndPeriod);
//The variable DT will now have the parsed date.
NewEndPeriod = DT.ToString("yyyy-MM-ddT00:00:00Z");
but I cannot figure out how to check if the first parse fails in order
to perform the second one
Instead of DateTime.ParseExact use DateTime.TryParseExact that will return a bool indicating if parsing was successful or not.
DateTime ModEndPeriod;
if (!DateTime.TryParseExact(GetEndPeriod,
format,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out ModEndPeriod))
{
//parsing failed
}
You can also use multiple formats for parsing using the DateTime.TryParse overload which takes an array of formats:
string[] formatArray = new [] { "dd MMMM yyyy","MMMM dd yyyy"};
DateTime ModEndPeriod;
if (!DateTime.TryParseExact(GetEndPeriod,
formatArray,
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out ModEndPeriod))
{
//parsing failed
}
Related
When giving "12-5" or "12,5" as an input to DateTime.TryParse in .NET, it is converting it to "12-05-2020" and the return value is true. How is "12-5" equal to "12-05-2020"? In my case, the input string is the user's date of birth and it is a free text as per the requirement and the parsed value "12-05-2020" makes no sense as the date of birth cant be a future date. Is there a way to correct this without using DateTime.Parse or DateTime.ParseExact as they might throw exceptions.
Well, you have 2 tests to perform:
For a valid date syntax (say, bla-bla-bla is not one)
For a valid date value (say, 25-03-2123 is not one)
Let's check for these requirements in one if:
string userInput = "12-05-15"; // 12 May 2015
...
// We can use several formats in one go:
// DateTime.TryParseExact will try formats in the given order
string[] allowedFormats = new string[] {
"d-M-yy", "d-M-yyyy", "MMM d yyyy",
};
if (DateTime.TryParseExact(
userInput.Trim(), // let's tolerate leading/trailing whitespaces
allowedFormats,
CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out var result) &&
result <= DateTime.Today &&
result >= DateTime.Today.AddYears(-150)) {
// result is
// 1. Valid date
// 2. At least 150 years ago
// 3. At most today
}
else {
// userInput doesn't meet at least one criterium
}
As #Rafalon suggested, use DateTime.TryParseExact to avoid exceptions and set the format you want.
string dateformat = "12-05";
bool answer = DateTime.TryParseExact(dateformat, "dd-MM-yyyy", CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out DateTime result);
I'm writing c# custom sonarqube rules. I'm trying to match a string literal in the code which is exactly like "dd/mm/yyyy".
I mean whenever developer used dd/mm/yyyy or mm/dd/yyyy or yyyy/mm/dd it should catch..
I need regular expression for this in c# to match the "dd/mm/yyyy or mm/dd/yyyy or yyyy/mm/dd"
As I wrote in the comments, you have a much bigger problem - your allowed formats are colliding - There is no way to distinguish between dd/mm/yyyy and mm/dd/yyyy if the day is lower than 13.
Also, validating date formats can easily be achieved using DateTime.TryParseExact so there really is no need to write a big, hard to read, hard to maintain regular expression for that.
Check out this demo program (click to run) I've written to illustrate what I mean:
public class Program
{
public static void Main(string[] args)
{
string[] dates = {
// Valid dates
"01/02/2018", // January 2nd (mm/dd/yyyy)
"04/01/2018", // January 4th (dd/mm/yyyy)
"20/01/2018", // January 20th (dd/mm/yyyy)
"01/21/2018", // January 21st (mm/dd/yyyy)
"2018/01/14", // January 14th (yyyy/mm/dd)
// Invalid dates
"23/13/2018",
"not a date",
"2018/22/01",
"1/1/18"
};
string[] formats = {"dd/MM/yyyy", "MM/dd/yyyy", "yyyy/MM/dd"};
for(var i = 0; i < dates.Length; i++)
{
DateTime dateTime;
if(DateTime.TryParseExact(dates[i], formats, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out dateTime))
{
Console.WriteLine(dates[i] + " is a valid date: "+ dateTime.ToString("yyyy-MM-dd") );
}
else
{
Console.WriteLine(dates[i] + " is invalid.");
}
}
}
}
And the results:
01/02/2018 is a valid date: 2018-02-01
04/01/2018 is a valid date: 2018-01-04 // Note: Wrong date! should be January 4th!
20/01/2018 is a valid date: 2018-01-20
01/21/2018 is a valid date: 2018-01-21
2018/01/14 is a valid date: 2018-01-14
23/13/2018 is invalid.
not a date is invalid.
2018/22/01 is invalid.
1/1/18 is invalid.
So, having written all that - the correct solution is to avoid string representation of datetime whenever possible, and if you really must allow that, you need to make sure you only allow a well defined set of formats that are not colliding each other - dd/mm/yyyy and yyyy/mm/dd are fine, if you want to add another option you can choose a different delimiter to help you correctly distinguish the values - dd/mm/yyyy and mm-dd-yyyy can live together quite happily, for instance.
Tihs regex will work for YYYY/MM/DD and DD/MM/YYYY:
((?=\d{4})\d{4}|(?=[a-zA-Z]{3})[a-zA-Z]{3}|\d{2})((?=\/)\/|\-)((?=[0-9]{2})[0-9]{2}|(?=[0-9]{1,2})[0-9]{1,2}|[a-zA-Z]{3})((?=\/)\/|\-)((?=[0-9]{4})[0-9]{4}|(?=[0-9]{2})[0-9]{2}|[a-zA-Z]{3})
How would you handle the following string value that needs to be converted to a DateTime object?
"2015/01/22 12:08:51 (GMT+09:00)"
Would like to include this as a recognized DateTime pattern. As I encounter other formats, I would like to just implement a new pattern.
Here a piece of code that will successfully parse the given string (notice DateTimeOffset rather than DateTime):
var str = "2015/01/22 12:08:51 (GMT+09:00)";
var dt = DateTimeOffset.ParseExact
(str,
"yyyy/MM/dd HH:mm:ss (\\G\\M\\TK)",
System.Globalization.CultureInfo.InvariantCulture
);
//dt now has +9:00 offset - that's correct only if GMT is provided as UTC.
More info at The Difference Between GMT and UTC
This code takes a string and converts it into a DateTime object
DateTime myDate = DateTime.Parse("2017-08-28 14:20:52,001", "yyyy-MM-dd HH:mm:ss,fff", System.Globalization.CultureInfo.InvariantCulture);
All you need to do is create a format that matches your input. This link helps:
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings
For more details read this: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/how-to-convert-a-string-to-a-datetime
Here there is the official documentation of DateTime.Parse with some examples. It covers also the case of other formats
https://msdn.microsoft.com/it-it/library/system.datetime.parse(v=vs.110).aspx
Using DateTime.ParseExact is probably your best bet. It takes in an input string and an expected format string that the input should match. It will return true if the conversion was successful, and the out parameter will be the result of the conversion (result in the example below).
I was unable to get it to work without forcibly removing the "GMT" portion, but if that's acceptable to you, the code below should work.
This example takes the original input and converts it to UTC time (i.e. it adjusts the time based on your GMT value, which is to subtract 9 hours in your example):
var input = "2015/01/22 12:08:51 (GMT-08:00)";
var format = "yyyy/MM/dd H:mm:ss (zzz)";
DateTime result;
// Remove the "GMT" portion of the input
input = input.Replace("GMT", "");
if (DateTime.TryParseExact(input, format, CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal, out result))
{
Console.WriteLine($"'{input}' converts to {result} UTC time.");
}
else
{
Console.WriteLine($"'{input}' is not in the correct format.");
}
This example is modified from the ones on the DateTime.TryParseExact documentation.
So I am getting the driver date from graphic card and display it into a TextBox but the value comes like this 20161216000000.000000-000 and I want to convert it into a real date.
I already got a function to convert this kind of dates, but it this case does does not work and after using it shows me like this 01-01-0001 00:00:00.
This is my function code:
private static string FormatDateTime(object ObjInstallDate)
{
object FinalDate = DBNull.Value;
string strDate = Convert.ToString(ObjInstallDate);
DateTime dtm;
DateTime.TryParseExact(strDate, new string[] { "yyyyMMdd", "yyyy-MM-dd", "dd-MM-yyyy" },
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out dtm);
if (!String.IsNullOrEmpty(strDate))
{
FinalDate = dtm;
}
return FinalDate.ToString();
}
Do you have any idea how I can get in this case 20161216000000.000000-000 something like 2016-12-16?
Taking a substring does the job (if the format is always like shown):
DateTime.TryParseExact(strDate.Substring(0, 8), "yyyyMMdd",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out DateTime dtm);
To get the required format to present the result you can use
dtm.ToString("yyyy-MM-dd");
After looking at your code and question it looks like the date you are passing to the function is not in correct/expected format that c# supports, that's why it is giving you the default system's beginnning date which is 01-01-0001 00:00:00 here.
But, as a workl around, as I can observe first 8 digit of the input value is date part, so you can use that in following way:
DateTime.TryParseExact(strDate.Substring(0, 8), "yyyyMMdd",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None, out dtm);
return dtm.ToString("yyyy-MM-dd");
You only needed to make sure your format matched your input, which none of your provided input formats did.
See how the custom dateformat specifiers and literal characters line-up with your input.
Your input: 20161216000000.000000-000
format specifiers: yyyyMMddhhmmss.ffffff-000
Bringing that format to your method you'll get this:
// takes an object, returns a DateTime or null in case of failure
DateTime FormatDateTime(object ObjInstallDate)
{
DateTime dtm;
if (!DateTime.TryParseExact(
(string) ObjInstallDate, // notice that we don't hassle with the input here,
// only cast to a string
// we simply rely on the parser of DateTimer.TryParseExact
"yyyyMMddhhmmss.ffffff-000", // this matches the format
// if the -000 represents a timezone
// you can use z00 or zz0
// don't use zzz as that expects -0:00
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out dtm))
{
// an invalid date was supplied, maybe throw, at least log
Console.WriteLine("{0} is not valid", ObjInstallDate);
}
// we either return here null or a valid date
return dtm; // !! No ToString() here
}
I cherry picked the needed custom format value from Custom Date and Time Format Strings.
Notice that I simply return the DateTime instance that was created. You'll see next why I do that.
As you want to display the DateTime on a Winform (I assume in a textbox, but an label will work as well) you can now simply Databind the DateTime instance to the textbox and let the databinding plumbing do the formatting. Here is a code example that can be run in LinqPad:
// take a string and make a date of it
var str = "20161216000000.000000-000";
DateTime dtm = FormatDateTime(str);
// show it on a Databind TextBox
var f = new Form();
var txt = new TextBox();
txt.Width = 200;
// bind the Text property
txt.DataBindings.Add(
"Text", // property on the textbox
dtm, // our DateTime object
null, // use the DateTime instance, not a property
true, // use formatting
DataSourceUpdateMode.OnValidation,
null, // value to indicate null
"yyyy-MM-dd"); // our format
f.Controls.Add(txt);
f.Show();
I'm using the overload of Add on the DataBindingsCollection that takes an Format string. I can then use the same custom format specifier options to represent that DateTime instance however I want. From here it would be easy to add another TextBox which uses the same DateTime instance but shows the month in text for example.
When all of this comes together this will be your result:
I have following strings in different formats:
16/05/2014
21-Jun-2014
2014-05-16
16-05-2014
5/19/2014
14 May 2014
I need to convert all the above strings into mm/dd/yyyy format in c#.
I have tried used DateTime.ParseExact as DateTime dt = DateTime.ParseExact("16-05-2014", "mm/dd/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture) in C# but i am getting the exception as "String was not recognized as a valid DateTime".
I have also tried to use to Convert.ToDateTime() but it is also not working.
Is there any method or function that we can write/available in C# that would convert the above string formats into a single date format i.e into "mm/dd/yyyy" format ??
Any help on this would be greatly appreciated.
It fails on the very first term of your format string, which is telling the function to treat the "16" as minutes and to look for hours, minutes, and seconds that don't exist in the input.
You have several different date formats, and so need the ParseExact() overload that accepts several different format strings:
string[] formats= {"dd/MM/yyyy", "dd-MMM-yyyy", "yyyy-MM-dd",
"dd-MM-yyyy", "M/d/yyyy", "dd MMM yyyy"};
string converted = DateTime.ParseExact("16-05-2014", formats, CultureInfo.InvariantCulture, DateTimeStyles.None).ToString("MM/dd/yyyy");
Also remember that lower case "m"s are for minutes. If you want months, you need an upper case "M". Full documentation on format strings is here:
http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx
Finally, I suspect you are getting ahead of yourself on formatting the output as a string. Keep these values as DateTime objects for as long as possible, and only format to a string at the last possible moment before showing them to the user. If you really do want a string, at least stick with the ISO 8601 standard format.
Your main problem is that your format string is wrong. A small m is for minute, a big M is for month.
Try to pass all your formats in an array. For example like this
DateTime.ParseExact("16-05-2014",
new[] {"dd/MM/yyyy", "dd-MMM-yyyy", "yyyy-MM-dd",
"dd-MM-yyyy", "M/d/yyyy", "dd MMM yyyy"},
CultureInfo.InvariantCulture, DateTimeStyles.None);
With this you can parse all your formats at once.
For more information about the format settings, see the official docs.
Few things:
Your input date 16/05/2014 doesn't match your format Month/Day/Year - how can there be a 16th month?
Secondly, you're using mm which represents Minutes, not Months. You should use MM.
Finally, your sample string 16-05-2014 doesn't match the format provided, you've used hyphens - instead of forward slashes /
Supply a collection of different formats matching your input:
string[] formats = new [] { "MM/dd/yyyy", "dd-MMM-yyyy",
"yyyy-MM-dd", "dd-MM-yyyy", "dd MMM yyyy" };
DateTime dt = DateTime.ParseExact("05-16-2014", formats, CultureInfo.InvariantCulture, DateTimeStyles.None);
You might find the following method useful to accept whatever date format you want and convert it to DateTime:
public DateTime? DTNullable(string DateTimestring, string CurrDateTimeFormat)
{
if (string.IsNullOrEmpty(DateTimestring)) return null;
else
{
DateTime datetimeNotNull;
DateTime.TryParseExact(DateTimestring, CurrDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out datetimeNotNull);
return datetimeNotNull;
}
}
Pass in your desired string to be converted to DateTime along with it's current date time format and this would return you a nullable DateTime. If you're certain that whatever string you're passing in won't be null then you can remove that bit. The reason for it being there is that you can't convert a null to DateTime. In my case I couldn't be certain if it would be or not so I needed the ability to capture nulls as well.
You can use it like this:
DateTime? MyDateTime = DTNullable(MyStartDate, "dd/MM/yyyy");
If you wanted you could alter the method to accept an array of strings and simply iterate through each and return them all in a list if they were of the same format.
As others have pointed out, months are MM not mm (minutes).
On a DateTime object you can call .ToString("MM/dd/yyyy"). Given the strings you have, you can first create new DateTime objects for each string and then call .ToString("MM/dd/yyyy"). For example:
var dateAsMmDdYyyy = DateTime.Now.ToString("MM/dd/yyyy");