DateTime.TryParse issue with dates consisting of a.m instead of am - c#

I have the following date in string format "2017-04-05 05:00:00 a.m" . Now I am trying to convert that to datetime format with the following code:
var dateTime="2017-04-05 05:00:00 a.m";
DateTime value = DateTime.MinValue;
DateTime.TryParse(dateTime, out value );
But I am alwayws getting dt as {1/1/0001 12:00:00 AM} , Can you please tell me why ? and how can I convert that string to date.

You could try creating a custom DateTimeFormatInfo with your custom am/pm designators:
var formatInfo = (DateTimeFormatInfo) CultureInfo.InvariantCulture.DateTimeFormat.Clone();
formatInfo.AMDesignator = "a.m";
formatInfo.PMDesignator = "p.m";
var value = DateTime.Parse("2017-04-05 05:00:00 a.m", formatInfo);
This also works for afternoon times:
var value = DateTime.Parse("2017-04-05 03:00:00 p.m", formatInfo);

The DateTime string you have is not parsed and you are getting the default value. One of the reason is the a.m in your date string. It also depends on Current thread Culture settings as well. You can use TryParseExact to give the format you have in DateTime string also with CulureInfo.
DateTime.TryParseExact(dateTime, "yyyy-MM-dd hh:mm:ss 'a.m'", CultureInfo.InvariantCulture,DateTimeStyles.None, out value);
Note you have a.m instead of am which has to be escaped like I did with 'a.m' in above example.
You can have p.m as well and above wont work for that. You can replace dot with empty string to make a.m to am and p.m to pm to use Custom Date and Time Format Strings tt for am / pm. I assume there would be only one dot between am or pm.
string dateTime = "2017-04-05 05:00:00 a.m";
dateTime = dateTime.Replace(".", "");
DateTime value = DateTime.MinValue;
DateTime.TryParseExact(dateTime, "yyyy-MM-dd hh:mm:ss tt", CultureInfo.InvariantCulture,DateTimeStyles.None, out value);
Read more about impact of Thread.CurrentCulture
The CultureInfo object that is returned by this property, together
with its associated objects, determine the default format for dates,
times, numbers, currency values, the sorting order of text, casing
conventions, and string comparisons. See the CultureInfo class to
learn about culture names and identifiers, the differences between
invariant, neutral, and specific cultures, and the way culture
information affects threads and application domains. See the
CultureInfo.CurrentCulture property to learn how a thread's default
culture is determined, and how users set culture information for their
computers.

The . in a.m is causing the problem. Assuming that you have both a.m and p.m to deal with, try stripping the . characters before you try to parse the DateTime value.
var stringToParse = "2017-04-05 05:00:00 a.m";
DateTime parsedValue;
DateTime.TryParse(stringToParse.Replace(".", string.Empty), out parsedValue);
This will not work if a . character is used elsewhere in the string, for any other reason. Fractional seconds for example. If that is the case, you'd be better off using Joe's answer instead.

Related

DateTime Format - Any System Datetime.now to "DD/MM/YYYY hh:mm:ss"

I have a program that do several things.
Two of them is read a date from a txt and rewrite a date in the same txt.
The read of the date is a regex expression like:
[0-9]{2}/[0-9]{2}/[0-9]{4} [0-9]{2}:[0-9]{2}:[0-5]{1}[0-9]{1})
The problem is that my regex expression only works in the format
"DD/MM/YYYY hh:mm:ss" and its impossible to make sure my regex expression can match all system datetime formats.
So, I need to make sure my program run's in every system, regardless the system datetime.now.
For that, i thought about format every system datetime.now, at start, to the format mentioned "DD/MM/YYYY hh:mm:ss".
At the moment i have the following code:
Datetime currentDate = DateTime.ParseExact(DateTime.Now.ToString(), "DD/MM/YYYY hh:mm:ss", CultureInfo.InvariantCulture);
However, when running some tests, using a system date in format "D/M/YYYY h:m:s" i get the error:
"String was not recognized as a valid DateTime."
The problem is that if my date, for example, is "9/27/2019 04:26:46"(M/D/YYYY h:m:s) it can't fit in the format i defined.
Any idea?
Thank you in advance!
You need to use the same format string and culture in every place where you convert the DateTime to string as well. In your sample code, you're doing
DateTime.Now.ToString()
This uses the default culture for the thread, and the default format. Unless assigned otherwise, the thread is probably using the local culture info. Instead, you would want to use the same format and the invariant culture:
DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
(note the lowercase "dd". "DD" is not a valid format specifier for date times; these things are case sensitive. Also note the "HH", which gives a 24-hour value, rather than 12-hour)
In practice, just using the invariant culture should be enough for persistence. Cultures already include default datetime formats, so unless you have a specific need to use a different format, why not use the default?
Also note that DateTime doesn't have a format. The format only comes into play when you convert from or to a string. That is the place where you need to ensure the same culture and format is used for both sides of the operation (and that's why for persistence, especially for data shared between different users or computers, you generally want to use the invariant culture).
If you need
to make sure my program run's in every system, regardless the system datetime.now
you can adapt international standard for this, say, ISO 8601.
In order to validate the DateTime, regular expressions like you have are not enough (just imagine leap years), but TryParse does it job:
string source = "2019-09-26T23:45:59";
// Either current culture date and time format or ISO
bool isValid = DateTime.TryParse(
source,
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal,
out var _date);
Or if you want to be more restrictive use TryParseExact:
// ISO only
bool isValid = DateTime.TryParseExact(
source,
"s",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal,
out var _date);
If you want to represent DateTime.Now in ISO 8601, add "s" standard format string:
string dateAsString = DateTime.Now.ToString("s");
Alas, you can provide a bunch of formats which are able to cope with any date and time formats; a classical example of ambiguous date is
01/02/03 - 01 Feb 2003 (Russia)
01/02/03 - 02 Jan 2003 (USA)
01/02/03 - 03 Feb 2001 (China)
You can alleviate the problem, while providing several formats:
// Here we try to support 4 formats (note different delimeters)
string[] formats = new string[] {
"s", // try ISO first
"dd'.'MM'.'yyyy HH':'mm':'ss", // if failed try Russian
"MM'/'dd'/'yyyy HH':'mm':'ss", // on error have a look at USA
"yyyy'-'MM'-'dd HH':'mm':'ss", // the last hope is Chinese
};
bool isValid = DateTime.TryParse(
source,
formats,
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeLocal,
out var date);

DateTime ParseExact not working when changing time

I'm having trouble figuring out why my date is parsed correctly until I change the time of the date passed into the parse method.
var parsedDate = DateTime.ParseExact("2016-02-05T07:00:00+00:00", "yyyy-MM-ddThh:mm:ss+00:00", CultureInfo.InvariantCulture);
dateValueToTryParse = parsedDate.ToString("dd/MM/yyyy");
The required result is outputted and I do get 05/02/2016. However, if I change the string passed in to:
2016-02-19T23:59:00+00:00
The output of dateValueToTryParse remains the same and it is not parsed correctly. Am I doing anything particularly wrong with my parsing? I'm confused as the format seems to be exactly the same?
You need to change your incoming format to yyyy-MM-ddTHH:mm:ss+00:00.
The difference is HH. Capital H means 24 hour clock or "military time".
Otherwise, it is trying to parse hour 23 which doesn't exist.
See here for more detailed information on other formats: https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx
Changing hh to HH specifier can solve your problem but since your string has an UTC offset value, I would prefer to parse it to DateTimeOffset instead of DateTime for consistency.
var dto = DateTimeOffset.ParseExact("2016-02-05T23:00:00+00:00",
"yyyy-MM-ddTHH:mm:sszzz",
CultureInfo.InvariantCulture);
Now, you have a DateTimeOffset as {05.02.2016 23:00:00 +00:00} and you can use it's .DateTime property to get the DateTime value represented by it.
var dateValueToTryParse = dto.DateTime.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
This will generate 05/02/2016 as a result.

DateTime Converted to Invalid Format

I tried converting 9/29/2013 2:44:28 PM (mm/dd/yyyy) to dd/mm/yyyy format.
I got a strange Date after Converting.
I tried
dateTimeVar.ToString("dd/mm/yyyy");
29/44/2013
The Date was a type of DateTime itself.
Lowercase mm means minutes, try this instead:
dateTimeVar.ToString("dd/MM/yyyy");
However, if this works depends on your local culture. If your current culture's date separator is different, / will be replaced with that. So if you want to enforce it use CultureInfo.InvariantCulture:
dateTimeVar.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
MM is for months, mm is for minutes. That's why it gets your minutes (which is 44) instead of your month value.
Use it like;
dateTimeVar.ToString("dd/MM/yyyy");
Check out;
The "MM" Custom Format Specifier
The "mm" Custom Format Specifier
And remember, / has special meaning when you use it as a date separator. It replace itself with your current culture date separator. Forcing to use with InvariantCulture would be better.
dateTimeVar.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
Take a look at;
The "/" Custom Format Specifier
What if I want to convert a string in dd/MM/yyyy to DateTime?
Then you can use DateTime.ParseExact method.
Converts the specified string representation of a date and time to its
DateTime equivalent using the specified format and culture-specific
format information. The format of the string representation must match
the specified format exactly.
As an example;
string s = "01/01/2013";
DateTime dt = DateTime.ParseExact(s, "dd/MM/yyyy", CultureInfo.InvariantCulture);
Console.WriteLine(dt);
Output will be;
1/1/2013 12:00:00 AM
Here a DEMO.
dateTimeVar.ToString("dd/mm/yyyy"); // Change to dd/MM/yyyy
The problem is mm stands for minute and you need MM which would be months
Tim's answer is correct, but to remove the format string altogether you can use. 'ToShortDateString'
DateTime date = DateTime.Today;
var stringDate = date.ToShortDateString();
var stringDate2 = date.ToString("dd/MM/yyyy");

DateTime.Parse, Latvian culture settings

I am sending in a string in dd/MM/yyyy format, which is then being parsed into lv-LV culture as set per the web.config globalization setting.
I am then comparing the date to DateTime.Now to see if it is in the past.
The problem is, DateTime.Parse converts my string to dd.MM.yyyy format, but DateTime.Now has MM.dd.yyyy format, so the comparison always fails.
Why would DateTime.Now be different to the output from DateTime.Parse, on the same thread culture?
Thanks!
(Update) This is the code I am using:
InputText contains input from a form in DD.MM.YYYY format
DateTime date = DateTime.Parse(InputText, CultureInfo.CurrentCulture);
// Check it's not in the past
this.IsValid = (date.CompareTo(DateTime.Now) > 0);
[DateTime.Now] in this context is in MM.DD.YYYY format using lv-LV cultureInfo
[date] is in DD.MM.YYYY format after the DateTime.Parse
A DateTime does not have formatting - it is simply a point in time.
If you are viewing it, that means you are outputting it. Use the correct culture to output the date.
DateTime.ToString has overloads that take a format provider such as a CultureInfo:
string formatted = DateTime.ToString(new CultureInfo("lv-LV"));
If not specified (in code or configuration), the default system culture will be used (or CultureInfo.InvariantCulture, in some cases).
If you just want to compare the 2 dates, you don't need to convert to string first.
DateTime myDate = DateTime.Parse(myDateAsString);//with the correct locale to ensure it's correctly parsed
if (myDate < DateTime.Now)
{
//it's in the past
}

datetime in c# how to change the default returned value to 24hrs?

yes what returned can be formatted using HH to display value in 24hrs,
but is there a way to make this the default returned value.?
Instead of playing with Cultures, make an extension method:
public static class Extensions
{
public static string To24HourTime(this DateTime dateTime)
{
return dateTime.ToString("HH:mm:ss");
}
}
You can use the method as follows then:
DateTime.Now.To24HourTime();
The internal representation is not relevant. If you are returning a DateTime, it will be a DateTime.
If you want to format the DateTime for display, then you need to use a format string to display it in whatever format you want.
See MSDN for the different custom datatime format strings.
DateTime date1;
date1 = new DateTime(2008, 1, 1, 18, 9, 1);
Console.WriteLine(date1.ToString("hh:mm:ss tt",
CultureInfo.InvariantCulture));
// Displays 06:09:01 PM
Console.WriteLine(date1.ToString("HH:mm:ss",
CultureInfo.InvariantCulture));
// Displays 18:09:01
The hh format specifier will return 12 hour based hours.
The tt format specifier will return the AM/PM designator.
The HH format specifier will return 24 hour based hours.
You can, as others have pointed out, change the thread cultures to a culture that uses 24 hours by default, but this will also effect formatting of numbers (decimal and thousands separators, for instance).
Change the CultureInfo on the current thread to a Culture that has 24hrs as default.
//In Sweden we use 24hrs format.
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("sv-se");
Edit: You could also just change the time format for the current culture info.
Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongTimePattern = "HH:mm:ss";
Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortTimePattern = "HH:mm";
//DateTime.ToString() will output something like (en-us culture) 8/21/2010 10:11:37
This depends on which culture your program is running on. Check the System.Threading.Thread.CurrentThread.CurrentCulture and CurrentUICulture properties and set these accordingly.
The CultureInfo type, among other tings, tells how numbers and dates are formatted. The DateTimeFormat property is what you are interested in. If you need a specialized culture you can create one and set its DateTimeFormat to whatever you need, and then assign it to the CurrentCulture property.
Most probably you just want to select a pre-defined culture. Read more here: http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx

Categories

Resources