convert string in unknown format to date in c# - c#

I have searched stackoverflow for an answer but no luck. I am developing a windows application and I have some strings in different date formats,
eg.
dd/MM/yyyy
MM/dd/yyyy
MM-dd-yyyy
dd-MM-yyyy
dd/MM/yyyy hh:mm::ss
MM/dd/yyyy hh:mm::ss
etc...
But I need to convert in to a common format - dd/MM/yyyy. The application can run in any windows machines in different culture.
What is the correct way to do it?
EDIT: One more thing I may not know what the format of incoming string.
Thanks in advance.

Use DateTime.ParseExact with the different patterns as formats.
If after parsing you really need to use a string representation, use the ToString method of the DateTime with the explicit format that you're interested in (so that it is culture-invariant). It's better however to keep the DateTime because this is format-agnostic.

You could distinguish between those formats that use different separators (i.e. "/" vs "-"). But how would you know if date such as 10/11/2010 represents 10th of November or 11th of October? If one number is not bigger than 12, there is no reliable way to do this without knowing an exact format.
As others have pointed out, if you do know the exact format, then you can use DateTime.ParseExact.

If you are processing some import file with a lot of dates in the same unknown format, you could try different formats and hope there is exactly one that doesn't give format errors.
Or to put it another way: split the "dates" into three numbers and check the range of values for each of those numbers. Values > 1900 will be years. If you find values from 1 to 31, those will be days.
Values from 1 to 12 might be months, but could also be days. Try and identify each of the parts.
The best way is to ask the supplier of those dates for the format.

To run this program on different culture, i think you should creat a function to indentify the culture of this string format and then use Datetime.Parse

Related

DateTime.TryParse issue, may relate to Globalization Setting in IIS

Basically,I am reading excel file where one of that columns has date format like : dd/MM/yyyy eg: 11/04/2016
When I am using DateTime.TryParse() to parse that string into datetime method TryParse() treated first numbers like month (number 11 in example above). However the same code running on the other computers will take the second number (04 in example above) as the month.
So my question is why there is a difference between them, what actually decide the behavior of TryParse method?
I think the main difference is in IFormatProvider (hard to say if I can't check some settings in target system), but I usually use other method to get proper DateTime object:
DateTime someDate = DateTime.ParseExact(myStringDate, "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
It always gives me what I want no matter how client environment is configured.
Hope this helps. :)
From DateTime.TryParse(String, DateTime) documentation:
Because the DateTime.TryParse(String, DateTime) method tries to parse
the string representation of a date and time using the formatting
rules of the current culture, trying to parse a particular string
across different cultures can either fail or return different results.
If a specific date and time format will be parsed across different
locales, use the
DateTime.TryParse(String, IFormatProvider, DateTimeStyles, DateTime)
method or one of the overloads of the TryParseExact method and provide
a format specifier.
That means your computers have different culture settings which is pointed in CurrentCulture property.
Looks like one computer's current culture have dd/MM/yyyy and the other computer's current culture have MM/dd/yyyy as a standard date and time format.
Since you are sure your values are always in dd/MM/yyyy format, I would use DateTime.ParseExact instead of Datetime.TryParse or DateTime.TryParseExact methods like;
var dt = DateTime.ParseExact(yourColumnValue, "dd/MM/yyyy", CultureInfo.InvariantCulture);
Or you can sets all computers current culture to like the first computer but remember, CultureInfo data is not a stable data that might be change in future with a windows update, .NET Framework version or OS version.

DateTime being weird

How come
w.WriteLine(Program.RegisterList[i].DateTime);
Writes : 11/20/2013 01:46:31 PM
But
w.WriteLine(Convert.ToDateTime(Program.RegisterList[i].DateTime, CultureInfo.InvariantCulture).ToString());
Writes 20/11/2013 1:46:31 PM
? Isn't invariant culture supposed to make it MM/DD/YY? I would like to use the invariant culture method incase a date slips by in DD/MM/YY format.
Thanks!
Edit: I should mention Program.RegisterList[i].DateTime is a string.
Edit2:
MessageBox.Show("11/20/2013 01:46:31 PM");
MessageBox.Show(Convert.ToDateTime("11/20/2013 01:46:31 PM", CultureInfo.InvariantCulture).ToString());
w.WriteLine(Convert.ToDateTime(Program.RegisterList[i].DateTime, CultureInfo.InvariantCulture).ToString());
You confused yourself by writing code you can't understand anymore. A simple rewrite of that one honking statement:
string s = Program.RegisterList[i].DateTime;
DateTime dt = Convert.ToDateTime(s, CultureInfo.InvariantCulture);
w.WriteLine(dt);
Which should now make it obvious that you are not using InvariantCulture to display the date, it uses the default culture. Which on your machine puts the day first.
Always write readable code, it is not slower.
CultureInvariant only guarantees that the format won't change across cultures - it should not be used to display data, only to persist data. If you're concerned about how a string is displayed, you should use a specific culture that displays how you want. More from MSDN
Having said that, I'm not sure what you mean by a "date slipping by" in a different format. Are you reading a list of dates, and some are in different format? If so, I'm afraid CultureInvariant is not the answer.

get the format of a string date in c#

I have a string date like 'Wednesday, May 15, 2013' when I Parse it o lost the original format, is there a way to know what was the original format date or get it before the final Parse?
No, you'll lose the original format, if will now be a different object type with no care for its original format prior to parsing.
Your best option would be to store the pre-parse format prior to parsing as a different variable.
However if you simply wish to format the date in that original format, see Farhad's answer.
You can use this for getting date in a fromat you wish.
String.Format("{0:D}", DateTime.Now); // Tuseday, May 21, 2013
The DateTime struct does not have a format, it stores all of those values on various properties. When you want to display it you specify which format to use.
Using a format specifier when displaying it will likely do what you want. This mdsn article provides some basic information on format specifiers. The only way you can use the exact format you show there is if you know it ahead of time and have a format specifier for it. If you know you'll want to display strings in that format throughout the program it will be easy, if you get many different formats and want to decide how to display your dt at runtime it will be fairly complicated. I'm sure you could write some code to figure out what it is, but once the DateTime is created it will have no notion of what format the string used to create it was in.

Change date to Universal Time Format changes my date wrongly I can't get error

I am trying to simply change the date format from the datatable to universal time format but it formats it wrongly as if I have date for August 7 it changed it to August 8 after formatting it to universal date time. My code for formatting date is,
DateVar[runs] = DateTime.Parse(Convert.ToString(output.Tables[0].Rows[runs][0])).ToUniversalTime().ToString();
Don't get in to code its correct and its a part of loop so "run" is loop and output is data set having one table I have first data in table is "Sunday, August 07, 2011 10:52 PM" and it was converted to "8/8/2011 5:52:00 AM" after implementing universal time format.
Hopes for your suggestions
Universal time isn't a format - it's a time zone, effectively. It's not clear what you're trying to do, but converting a "local" DateTime to "universal" DateTime will usually change the time. If you don't want that to happen, don't call ToUniversalTime.
It's a pity that the .NET date/time API isn't as clear as it could be - the DateTime type itself has some horrible ambiguities about it. I'm trying to improve the situation with my Noda Time project, but you will need to understand what time zones are about etc.
Personally I would suggest not using simply DateTime.Parse or just calling ToString unless you're absolutely sure that the default format is what you want. I usually call DateTime.ParseExact and specify the expected format (and usually CultureInfo.InvariantCulture unless it's a user-entered string) - and likewise I provide a format string to the ToString call.
In your code you're simply converting a string to a string - what are you attempting to accomplish? If you're just trying to change the format (e.g. to dd/MM/yyyyTHH:mm:ss) then you don't need to call ToUniversalTime but you do need to provide the format string.
I suggest you split your code out into several statements to help you debug this (and for general code clarity):
Fetch the string from the DataTable, if you really need to (if it's already a DateTime, there's no point in converting it to a string and then back again)
Parse the string (again, assuming you need to)
Perform any conversions you need to
Format the DateTime with an explicit format string
Now if any single operation is causing a problem, you can isolate it more easily.
If I run ToUniversalTime() from Greenwich it will give same time but if i do it while I live some where else it will get an offset date time object of + or - hours depending on position.

Parsing dates without all values specified

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.

Categories

Resources