Converting date string in unknown format to datetime c# - c#

I don't know format of the DateTime because web page has more than one language and more than one Datetime format are available. I had to change poland dateformat in datepicker UI to d.m.yyyy although ISO standard is YYYY-mm-dd. .NET uses ISO standard but whenever I try to use Convert.ToDateTime(stringDate) I get exception String is not recognized as valid DateTime . I tried using Convert.ToDateTime(stringDate,CultureInfo.InvariantCulture) but it does not help. How to successfully convert to DateTime?
Example:
item.arrival is string which can be in more than 10 formats. Convert.ToDateTime works for them all.
BUT:
item.arrival dateformat for poland language is not anymore yyyy-mm-dd (because I had requirement to change it) so Convert.ToDateTime not works anymore only for poland language. New format is 13.06.2015. Because of that, because format is not ISO standard for poland language .NET fails to do conversion. I hope it is more clear now.
ArrivalDate = Convert.ToDateTime(item.arrival, CultureInfo.InvariantCulture),

I had to change poland dateformat in datepicker UI to d.m.yyyy
...
Example: item.arrival is string which can be in more than 10 formats. Convert.ToDateTime works for them all. BUT: item.arrival dateformat for poland language is not anymore yyyy-mm-dd (because I had requirement to change it)
Based upon what you say, your date time conversion works for all but Polish, and you (in your code) know when it is Polish. So, handle Polish special using the format you have been required to use, and handle the other nine normally.

This is what I did. I put it inside some PageBase class so it should more general and less error prone solution than some "if-poland-date" statements around the project.
CultureInfo newCulture = (CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture;
if (newCulture.TwoLetterISOLanguageName == "pl")
{
DateTimeFormatInfo myDTFI = new CultureInfo("hr-HR", false).DateTimeFormat;
newCulture.DateTimeFormat = myDTFI;
CultureInfo ci = new CultureInfo("pl-PL");
DateTimeFormatInfo dateformat = new DateTimeFormatInfo();
ci.DateTimeFormat = myDTFI;
CultureAndRegionInfoBuilder obj = new CultureAndRegionInfoBuilder("pl-PL", CultureAndRegionModifiers.Replacement);
obj.LoadDataFromCultureInfo(ci);
CultureAndRegionInfoBuilder.Unregister("pl-PL");
obj.Register();
}

Related

How to correctly render a ar-SA date and time string

So, I've got a DateTime value, and I need to render it out using the ar-SA culture (using the Gregorian Calendar).
The format I'd like to use is dd-MMM-yyyy HH:mm.
I'm using this currently to format it -
dateTimeValue.ToString("dd-MMM-yyyy HH:mm", culture)
In en-GB, I'd see -
06-Jun-2017 16:49
In ar-SA, when I use the same method, I see -
06-يونيو-2017 16:49
Now, from what I can work out, I think it's the RTL string that's causing the problem, since it's always on the right-hand side.
How do I render out this date correctly in RTL?
Right, after a bit of digging, I've managed to get a solution that works.
Even though my question was originally about ar-SA, it does apply to any right-to-left culture.
I ended up using unicode characters to explicitly state what parts of the string were left-to-right and right-to-left.
So, using the constants -
private const char LeftToRightCharacter = (char)0x200E;
private const char RightToLeftCharacter = (char)0x200F;
I can then build up a string of the date as follows -
if (culture.TextInfo.IsRightToLeft)
{
return
LeftToRightCharacter +
date.ToString("yyyy-", culture) +
RightToLeftCharacter +
date.ToString("MMM", culture) +
LeftToRightCharacter +
date.ToString("-dd", culture);
}
return date.ToString("dd-MMM-yyyy", culture);
...where culture is a CultureInfo (with the DateTimeFormat.Calendar set to new GregorianCalendar()) and date is a DateTime.
So, for the date 06-Jun-2017, in en-GB I get -
06-Jun-2017
and in ar-SA I get -
2017-‏يونيو‎-06
Now that I've got that as a string, I can add the time on either side (to the left, if the culture is RTL and on the right if the culture is LTR).
It was useful seeing how Unicode deals with these characters, along with the other characters I could have used instead - http://www.unicode.org/reports/tr9/
CultureInfo CurrentCulture = CultureInfo.GetCultureInfo("ar-AE");
string text = DateTime.Now.ToString("yyyy MMMM dd", CurrentCulture);
var dt = DateTime.Parse("31/1/2016 12:00 AM", CultureInfo.GetCultureInfo("ar-SA"));
// Throws FormatException
And you can't parse this string with ar-SA culture because this culture uses ص as a AMDesignator since it uses UmAlQuraCalendar rather than a GregorianCalendar.
You can use InvariantCulture (which uses AM as a AMDesignator and uses GregorianCalendar) instead with DateTime.ParseExact method with specify it's format exactly.
string s = "31/1/2016 12:00 AM";
DateTime dt = DateTime.ParseExact(s, "dd/M/yyyy hh:mm tt",CultureInfo.InvariantCulture);
Reference here. Someone had the same problem as you more or less and this seemed to have solved the error. Hope this helps.
To render it go have a look here and here. They seemed to have a similar issue with the rendering that may be able to resolve your issue.
The ar-SA short date pattern is:
d[U+200F]‏/M‏[U+200F]/yyyy g for dotnet v6.0.1
MM/dd/yyyy for date-fns/locale/ar-SA v4.26
U+200F is the Right-To-Left mark character.
It shows up as "d‏/M‏/yyyy g" if you print it out.
Not sure what is the final "g", maybe the era (in case why it is not "G"?)
Also the "g" is not accepted by the date-fns.format() function and raises an error.
open System
open System.Globalization
open System.IO
let culture = CultureInfo.GetCultureInfo("ar-SA")
let pattern = culture.DateTimeFormat.ShortDatePattern
let date1 = DateTime(2017, 6, 6).ToString(pattern)
let date2 = DateTime(2017, 6, 6).ToString(pattern, culture)
use writer = File.CreateText("C://temp//ar-SA date.txt")
writer.WriteLine $"Short date1: {date1}"
writer.WriteLine $"Short date2: {date2}"
Result, copy paste from notepad++:
Short date1: 6‏/6‏/2017 AD <- bad rendering here in the post
Short date2: 11‏‏/9‏‏/1438 بعد الهجرة <- bad rendering here in the post
In notepad++ the "6" and "11" appears in the right place:
So, the "wrong" position seems to really be a matter of where the date is printed (HTML, text file ...).
When you change the culture of the current thread it correctly uses the Hijri calendar so the year is 1438.
I added an extra RLM marker to the pattern (before the day):
"‏[U+200F]d[U+200F]‏/M[U+200F]‏/yyyy g"
and it came out correct both in notepad++ and copy-pasted here:
Short date3: ‏11‏‏/9‏‏/1438 بعد الهجرة

Transform between datetime formats

I am facing a problem in which I need to transform dates in a given input format into a target one. Is there any standard way to do this in C#?
As an example say we have yyyy.MM.dd as the source format and the target format is MM/dd/yyy (current culture).
The problem arises since I am using a parsing strategy that gives priority to the current culture and then if it fails it tries to parse from a list of known formats. Now say we have two equivalent dates one in the source culture above (2015.12.9) and the other in the current culture (9/12/2015). Then if we attempt to parse this two dates the month will be 12 for the first case and in the second will be 9, so we have an inconsistency (they were supposed to mean be the same exact date).
I believe that if existing it should be something as
DateTime.Convert(2015.12.9, 'yyyy/MM/dd', CultureInfo.CurrentCulture).
Any ideas?
EDIT:
Thank you all for your ideas and suggestions, however the interpretation most of you gave to my question was not quite right. What most of you have answered is a direct parse in the given format and then a conversion to the CurrentCulture.
DateTime.ParseExact("2015.12.9", "yyyy.MM.dd", CultureInfo.CurrentCulture)
This will still return 12 as month, although it is in the CurrentCulture format. My question thus was, is there any standard way to transform the date in yyyy.MM.d to the format MM/dd/yyy so that the month is now in the correct place and THEN parsed it in the target culture. Such function is likely to be unexisting.
DateTime.ParseExact is what you are looking for:
DateTime parsedDate = DateTime.ParseExact("2015.12.9", "yyyy.MM.d", CultureInfo.InvariantCulture);
Or eventualy DateTime.TryParseExact if you're not confident with input string.
I know it's late but I try to explain little bit deep if you let me..
I am facing a problem in which I need to transform dates in any format
to a target one.
There no such a thing as dates in any format. A DateTime does not have any implicit format. It just has date and time values. Looks like you have a string which formatted as date and you want to convert another string with different format.
Is there any standard way to do this in C#?
Yes. You can parse your string with DateTime.ParseExact or DateTime.TryParseExact first with specific format to DateTime and then generate it's string representation with a different format.
As an example say we have yyyy.MM.dd as the source format and the
target format is MM/dd/yyy (current culture).
I didn't understand what is the meaning of current culture in this sentences and I assume you want yyyy not yyy, but you can generate it as I described above like;
string source = "2015.12.9";
DateTime dt = DateTime.ParseExact(source, "yyyy.MM.d", CultureInfo.InvariantCulture);
string target = dt.ToString("MM/dd/yyyy", CultureInfo.InvariantCulture); // 12/09/201
The problem arises since I am using a parsing strategy that gives
priority to the current culture and then if it fails it tries to parse
from a list of known formats.
Since you didn't show any parsing strategy and there is no DateTime.Convert method in .NET Framework, I couldn't any comment.
Now say we have two equivalent dates one in the source culture above
(2015.12.9) and the other in the current culture (9/12/2015). Then if
we attempt to parse this two dates the month will be 12 and in the
second will be 9, so we have an inconsistency.
Again.. You don't have DateTime's. You have strings. And those formatted strings can't belong on any culture. Sure all cultures might parse or generate different string representations with the same format format a format does not belong any culture.
I assume you have 2 different string which different formatted and you wanna parse the input no matter which one it comes. In such a case, you can use DateTime.TryParseExact overload that takes string array for all possible formats as a parameter. Then generate it's string representation with MM/dd/yyy format and a culture that has / as a DateSeparator like InvariantCulture.
string s = "2015.12.9"; // or 9/12/2015
string[] formats = { "yyyy.MM.d", "d/MM/yyyy" };
DateTime dt;
if (DateTime.TryParseExact(s, formats, CultureInfo.InvariantCulture,
DateTimeStyles.None, out dt))
{
Console.WriteLine(dt.ToString("MM/dd/yyyy", CultureInfo.InvariantCulture));
}
The Simple and Best way to do it is Using .ToString() Method
See this code:
DateTime x =DateTime.Now;
To Convert This Just Write like This:
x.ToString("yyyyMMdd")//20151210
x.ToString("yyyy/MM/dd)//2015/12/10
x.ToString("yyyy/MMM/dd)//2015/DEC/10 //Careful About M type should be capital for month .
Hope helpful

DateTime.Parse not reversing month and day based on thread culture

I'm parsing a date string from a database so that I can display it in the current culture of the UI thread. For some reason, the date is not parsing with respect to the culture - specifically, I'm parsing a en-US date to switch to a es-ES date and the month/day positions are not switching.
According to this MSDN article I should just be able to use Parse with only the date string as a parameter. I should also be able to explicitly provide a culture object. Neither works and my date remains as mm/dd instead of dd/mm. I've verified that both the thread's CurrentCulture and CurrentUICulture are set properly and if I do a new DateTime, that outputs correctly.
Am I missing something?
EDIT: Nothing fancy in the code, just the .NET API.
CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
DateTime formattedDate = DateTime.Parse("5/9/2014");
formattedDate.ToShortDateString(); //this returns 5/9/2014
DateTime.Today.ToShortDateString(); //this returns 9/5/2014
The problem you are having is that 5/9/2014 is a perfectly valid month string in either dd/mm/yyyy or mm/dd/yyyy format so when you do DateTime.Parse("5/9/2014") it will successfully parse it as 5th September 2014 (since the es-es date format is dd/mm/yyyy).
This then explains why when you output you get something different to DateTime.Today (which is obviously 9th May).
A working version of your program would be:
var outputCulture = CultureInfo.CreateSpecificCulture("es-es");
var inputCulture = CultureInfo.CreateSpecificCulture("en-us");
Thread.CurrentThread.CurrentCulture = outputCulture;
Thread.CurrentThread.CurrentUICulture = outputCulture;
DateTime formattedDate = DateTime.Parse("5/9/2014", inputCulture);
Console.WriteLine(formattedDate.ToShortDateString()); //this returns 09/05/2014
Console.WriteLine(DateTime.Today.ToShortDateString()); //this returns 09/05/2014
As you see I am specifying the culture for input so that it knows to use the en-us culture rather than the explicitly set es-es culture for parsing.
Since you are parsing a string from a database, the only way to do this correctly is to persist the string in a standard format that does not depend on any culture specific data. ISO 8601 defines formats appropriate for this and you can use a custom format string to achieve this. You can also use .Net's 'o' format specifier for round trip. See How to: Round-trip Date and Time Values for more information.
Culture specific settings do change and cause items that used to parse, to no longer be able to parse even if you know the culture that was used to format the value with to start with.
Culture specific formatting and parsing is meant to be ephemeral and to be used to interact with the user only.

C# Date Conversion From Euro Time To en-US Time Needed For Date Calculations

I have a date that is entered through the system (from a database) as dd/mm/yy I need to programmatically convert the date to en-US format to mm/dd/yyyy so that I can do some date calculations within the code. The code that I have so far is:
String myJames = "25/04/13" // Date String comes in as non-US date
String myJames2 = System.DateTime.Today.ToString(myJames); // I think the problem is here
DateTime d1 = Convert.ToDateTime(myJames2);
DateTime d2 = DateTime.Now;
TimeSpan t = d2 - d1;
double NrOfDays = t.TotalDays;
I know this is not completely correct, especially in the first few lines. Any help getting the dates into one en-US format for effective comparisons would be greatly appreciated.
Just to check I understand your question. You have a date as a string and you want to convert that string into a datetime so you can use it in a calculation? And your problem is that the string isn't in the format that the locale the code is running in would use?
In which case use DateTime.ParseExact.
DateTime d1 = DateTime.ParseExact(myJames,"dd/MM/yy");
This line of code would replace your line declaring and assigning d1. The line assigning to myJames2 can be removed as it isn't needed.
Everytime you convert from or to a string, culturesettings are involved.
So.. if you are converting a DateTime to string, and your culture is en-US, it will automatically converted to: MM/dd/YYYY.
This is also true for converting back. If you convert a string back to a DateTime, the culturesettings are used to see what format the string is in.
Teh culture settings are always: Thread.CurrentThread.CurrentCulture.
Most conversion functions allow to override the format (like "MM/dd/yyyy") and/or the culture. So you can create your own culture and use this during conversions.
You say the database uses dd/MM/yy, but normaly a DateTime in a database is not formatted, it is just a binary value. Or is it stored as a text? If it is stored as a text, than you should ALWAYS convert it to a DateTime using the correct culture or format.

How to format a Date without using code - Format String Question

How can I achieve the following with a format string: Do 01.01.2009 ?
It has to work in all languages (the example would be for Germany). So there should only be the short weekday and then the short date.
I tried 'ddd d' (without the '). However, this leads to 'Do 01'.
Is there maybe a character I can put before the 'd' so that it is tread on its own or something like that?
DateTime.Now.ToString("ddd dd/MM/yyyy")
You should be using the ISO 8601 standard if you are targeting audiences with varied spoken languages.
DateTime.Now.ToString("ddd yyyy-MM-dd");
Alternatively, you can target the current culture with a short date:
DateTime.Now.ToString("d", Thread.CurrentThread.CurrentCulture);
or a long date:
DateTime.Now.ToString("D", Thread.CurrentThread.CurrentCulture);
To get the locale specific short date, as well as the locale day name then you're going to have to use two calls, so:
myDate.ToString("ddd ") + myDate.ToString("d");
Have you considered using the long date format instead?
If you want to localize (I assume so, since you said "all languages"), you can use CultureInfo to set the different cultures you want to display. The MSDN library has info on Standard Date and Time Format Strings and CultureInfo Class.
The example MSDN provides:
// Display using pt-BR culture's short date format
DateTime thisDate = new DateTime(2008, 3, 15);
CultureInfo culture = new CultureInfo("pt-BR");
Console.WriteLine(thisDate.ToString("d", culture)); // Displays 15/3/2008
Just for reference, in Java it goes like this:
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date date = new Date();
String formattedDate = dateFormat.format(date);
If you want to ensure the same characters are used as separators, you have to use a backslash to escape the character, otherwise it will default to the locale you are in. I recommend using this string if you want the format you specified in your question
DateTime.Now.ToString("ddd dd.MM.yyyy");
To use forward slashes instead, you should escape them so that they always output as slashes.
DateTime.Now.ToString("ddd dd\\/MM\\/yyyy");

Categories