How to create .NET CultureInfo with Dateformat ISO 8601? - c#

Is it possible to make .NET create the following output?
DateTime.UtcNow.ToString() --> "2017-11-07T00:40:00.123456Z"
Of course there is always the possibility to use ToString("s") or ToString("yyyy-MM-ddTHH:mm:ss.fffffffK"). But is there a way to adjust the default-behaviour for the parameterless ToString-Method to the desired output?
I tried changing the CurrentCulture. But the best I got was "2017-11-07 00:40:00.123456Z". I did not find a way to change the separator between the date and the time from a space to "T".

It is possible, but only by accessing an internal field via reflection, which is not guaranteed to work in all cases.
var culture = (CultureInfo) CultureInfo.InvariantCulture.Clone();
var field = typeof(DateTimeFormatInfo).GetField("generalLongTimePattern",
BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
// we found the internal field, set it
field.SetValue(culture.DateTimeFormat, "yyyy-MM-dd'T'HH:mm:ss.FFFFFFFK");
}
else
{
// fallback to setting the separate date and time patterns
culture.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd";
culture.DateTimeFormat.LongTimePattern = "HH:mm:ss.FFFFFFFK";
}
CultureInfo.CurrentCulture = culture;
Console.WriteLine(DateTime.UtcNow); // "2017-11-07T00:53:36.6922843Z"
Note that the ISO 8601 spec does allow a space to be used instead of a T. It's just preferable to use the T.

Scott Hanselmann has blogged about it here.
a little Reflectoring shows us that the default format string for System.DateTime is "G" as in System.DateTime.ToString("G") where G is one of the presets.
[...]
And gets the output he expects, indicating that "G" is the combination of a ShortDate and a LongTime.
So you should override ShortDatePattern and LongTimePattern:
I converted the code to C# and yes, it is working:
var customCulture = new CultureInfo("en-US")
{
DateTimeFormat =
{
ShortDatePattern = "yyyy-MM-dd",
LongTimePattern = "HH:mm:ss.FFFFFFFK"
}
};
Console.WriteLine(DateTime.Now);
System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
System.Threading.Thread.CurrentThread.CurrentUICulture = customCulture;
Console.WriteLine(DateTime.Now);
Console.ReadLine();
However, Scott has titled his post Enabling Evil for reason. Think twice before doing that!
The T is not needed, but also can not be provided. If you still need it, you need to use Reflection, as Matt answered.

Related

Convert(change) current DateTime as per culture in c#

if (!IsPostBack && !Page.IsCallback)
{
double OffsetHrs = GetTimeZoneOffsetFromCookie();
string dateFormat = ServiceManager.LocalizationService.GetString("AppHeaderTop", "DateFormat", "g");
CultureSelected CultureSelected = GetCultureSelected();
ASPxLabelCurrentTime.Text = DateTime.Now.ToUniversalTime().AddHours(-OffsetHrs).ToString(dateFormat);
if (CultureSelected.CultureCode != "en-US")
{
DateTimeFormatInfo usDtfi = new CultureInfo("en-US", false).DateTimeFormat;
DateTimeFormatInfo currentDtfi = new CultureInfo(CultureSelected.CultureCode, false).DateTimeFormat;
ASPxLabelCurrentTime.Text = Convert.ToDateTime(ASPxLabelCurrentTime.Text, usDtfi).ToString(currentDtfi.ShortDatePattern); //what can i Use here ?
}
Let say Output of ASPxLabelCurrentTime.Text
for en-US culture is 11/2/2015 4:14 PM (70)
If I select specific culture I want this datetime 11/2/2015 4:14 PM (70) to appear in that specific culture format.
Your question seems unclear but I try to give a shot.
First of all, what is this (70) exactly? Where is this came from? en-US culture can't parse this string without using it in a string literal delimiter with ParseExact or TryParseExact methods. On the other hand, since you assing ASPxLabelCurrentTime.Text the result of the DateTime.Now.ToUniversalTime().AddHours(-OffsetHrs).ToString(dateFormat) code, I don't believe this (70) part is really an issue on this question.
Second, If I understand clearly, the problem seems the usage of DateTime.ToString(string) method.
ASPxLabelCurrentTime.Text = Convert.ToDateTime(ASPxLabelCurrentTime.Text, usDtfi)
.ToString(currentDtfi.ShortDatePattern);
// ^^^ Problem seems here
Okey let's say you successfully parse this ASPxLabelCurrentTime.Text with usDtfi culture (which is en-US), but with this .ToString(string) method, you are not using currentDtfi settings actually, you are using CurrentCulture settings when you generate formatted string representation of your DateTime.
From DateTime.ToString(String) doc;
Converts the value of the current DateTime object to its equivalent
string representation using the specified format and the formatting
conventions of the current culture.
Since we don't know what GetCultureSelected method returns exactly, it may or may not be the same culture with currentDtfi.
I strongly suspect, you can solve this problem to using that culture as a second parameter in ToString method as;
ASPxLabelCurrentTime.Text = Convert.ToDateTime(ASPxLabelCurrentTime.Text, usDtfi)
.ToString(currentDtfi.ShortDatePattern, currentDtfi);
IF this (70) is really part of on your string, you need to ParseExact or TryParseExact methods to supply exact format of it.
string s = "11/2/2015 4:14 PM (70)";
DateTime dt;
if(DateTime.TryParseExact(s, "MM/d/yyyy h:mm tt '(70)'", CultureInfo.GetCultureInfo("en-US"),
DateTimeStyles.None, out dt))
{
ASPxLabelCurrentTime.Text = dt.ToString(currentDtfi.ShortDatePattern, currentDtfi);
}

How to get date only if time is 00:00:00 from DateTime c#

I want to convert DateTime object to string. What I want to achieve is following things:
Get Date only out of it if Time is 00:00:00.
Get Date and Time if both are present.
I want to achieve this using CurrentCulture.DateTimeFormat and
Convert.ToString(DateTime, IFormatProvider), otherwise I know how
to do this using .ToString() Extension method.
I have tried following things:
Thread.CurrentPrincipal = principal;
CultureInfo culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.DateTimeFormat.ShortDatePattern = MPAResource.DateFormat;
culture.DateTimeFormat.LongTimePattern = "hh:mm:ss tt";
culture.DateTimeFormat.ShortTimePattern = "hh:mm:ss tt";
culture.DateTimeFormat.FullDateTimePattern = MPAResource.DateTimeFormat;
Thread.CurrentThread.CurrentCulture = culture;
Then:
string x = Convert.ToString(x.ExpectedJoiningDate, CultureInfo.CurrentCulture);
Output is 09-Oct-2015 11:00 AM. I want 09-Oct-2015 11:00 AM if time is there and 09-Oct-2015 if time is not there.
But above line gives me only date even if time is present with date.
Seems to me like this is pretty straight forward:
var dt = x.ExpectedJoiningDate;
string x = (dt.TimeOfDay == TimeSpan.Zero)?dt.ToShortDateString():dt.ToString();
PS: you can use a culture as parameter in ToString if you like. See https://msdn.microsoft.com/en-us/library/aa326720(v=vs.71).aspx for details on how to do this.
Tim made the remark that the OP wants to use Convert.ToString. It doesn't compute, so I refuse. Why doesn't it compute? Here's the code for Convert.ToString:
public static string ToString(DateTime value, IFormatProvider provider)
{
return value.ToString(provider);
}
Yes people, that's basically the same.
That said, if you're stubborn, I guess you can implement IFormatProvider in your own little class, change the format provider based on the condition, then pass that instead of the default format provider. Then, congrats, you've created a lot of senseless code that gives the exact same results using Convert.ToString.
After a while a wrote method for myself.
public static string ConvertToMyDateTimeFormat(Nullable<DateTime> value, CultureInfo IFormateProvider)
{
if (value.HasValue)
{
if (value.Value.TimeOfDay.Ticks > 0)
{
return value.Value.ToString(IFormateProvider);
}
else
{
return value.Value.ToString(IFormateProvider.DateTimeFormat.ShortDatePattern);
}
}
else
{
return string.Empty;
}
}

How To Get English Month Name From Hebrew Calendar In C#

I am trying to output a Hebrew calendar date in English with C#. The following outputs the date in Hebrew:
var ci = System.Globalization.CultureInfo.CreateSpecificCulture("he-IL");
ci.DateTimeFormat.Calendar = new System.Globalization.HebrewCalendar();
Response.Write(DateTime.Today.ToString("MMM d, yyyy", ci));
Response.Write(DateTime.Today.ToString("d-M-y", ci));
Gives
כסלו כ"ו, תשע"ה
כ"ו-ג'-תשע"ה
for December 18, 2014. Change the CultureInfo to "en-US" raises an "Not a valid calendar for the given culture." error. I am trying to get
26 Kislev 5775
and
26-09-5775
I could not figure out how to set the array of month names for leap years or the array of day numbers so that they are rendered as English numbers rather than hebrew letters. My solution was:
Globals.cs
public static string[] HebrewMonthNames =
{
"Tishrei",
"Cheshvan",
"Kislev",
"Tevet",
"Shevat",
"Adar",
"Nissan",
"Iyar",
"Sivan",
"Tamuz",
"Av",
"Elul"
};
public static string[] HebrewMonthNamesLeapYear =
{
"Tishrei",
"Cheshvan",
"Kislev",
"Tevet",
"Shevat",
"Adar I",
"Adar II",
"Nissan",
"Iyar",
"Sivan",
"Tamuz",
"Av",
"Elul"
};
Utils.cs
public string FormatHebrewDate(DateTime dtGregorian)
{
System.Globalization.HebrewCalendar hCal = new System.Globalization.HebrewCalendar();
string sDate = hCal.GetDayOfMonth(dtGregorian).ToString() + " ";
if (hCal.IsLeapYear(hCal.GetYear(dtGregorian)))
{
sDate += Globals.HebrewMonthNamesLeapYear[hCal.GetMonth(dtGregorian) - 1];
}
else
{
sDate += Globals.HebrewMonthNames[hCal.GetMonth(dtGregorian) - 1];
}
sDate += " " + hCal.GetYear(dtGregorian).ToString();
return sDate;
}
Option 1:
You can override the DateTimeFormatInfo.MonthNames and MonthGenitiveNames properties as well as their corresponding AbbreviatedMonthNames and AbbreviatedMonthGenitiveNames properties.
They are simple 1-dimensional string[] arrays and have a public setters, which allows you to add your custom translations to the CultureInfo:
When this property is set, the array must be one-dimensional and must
have exactly 13 elements. Calendar objects accommodate calendars with
13 months. The first element (the element at index zero) represents
the first month of the year defined by the Calendar property.
If you set the MonthNames property, you must also set the
MonthGenitiveNames property.
If the custom pattern includes the format pattern "MMMM",
DateTime.ToString displays the value of MonthNames in place of the
"MMMM" in the format pattern.
This property is affected if the value of the Calendar property
changes.
So you could modify your code example to this:
// I am just using German Number representations for the example.
// Use additional string Arrays to suit the abbrevated
// and the Genetive names.
// Replaye with whatever suits your needs.
string[] monthNames =
{
"Eins",
"Zwei",
"Drei",
"Vier",
"Fünf",
"Sechs",
"Sieben",
"Acht",
"Neun",
"Zehn",
"Elf",
"Zwölf",
string.Empty
};
// Assign each string Array to its corresponding property.
// I am using the same Array here just as an example for
// what is possible and because I am lazy... :-)
ci.DateTimeFormat.MonthNames = monthNames;
ci.DateTimeFormat.MonthGenitiveNames = monthNames;
ci.DateTimeFormat.AbbreviatedMonthNames = monthNames;
ci.DateTimeFormat.AbbreviatedMonthGenitiveNames = monthNames;
These names will then be used in with your format string in the output, just as you want it to have.
Each time you change the calendar, these overrides will be lost. So you need to make sure to re-assign the custom values if you need it.
[Update] Option 2:
A more persistent approach might be to use the CultureAndRegionInfoBuilder Class.
Defines a custom culture that is new or based on another culture and
country/region. The custom culture can be installed on a computer and
subsequently used by any application that is running on that computer.
You can either create a complete replacement version of the "he-IL" culture or create a variation with just your custom translations, or anything in between.
Using this approach you do not have to manually make sure that the translations are in place after each Culture-switch in the appliaction like in Option 1. Once the new Custom Culture is registered, you can use it like any other CultureInfo.
Please note that your application will need administrative priviledges to register a new Custom Culture.
The creation of a Custom Culture is not too complicated as the following code snippet shows.
Example from MSDN: CultureAndRegionInfoBuilder
The following example defines a custom ru-US culture that represents
the Russian language in the United States. The example defines the
custom culture by loading settings from the Russian (Russia)
CultureInfo object and the U.S. RegionInfo object, and then sets a
number of CultureAndRegionInfoBuilder properties. The example
registers the custom culture, and then instantiates it and makes it
the current thread culture.
using System;
using System.Globalization;
using System.Threading;
public class Example
{
public static void Main()
{
// Create a custom culture for ru-US.
CultureAndRegionInfoBuilder car1 = new CultureAndRegionInfoBuilder("ru-US",
CultureAndRegionModifiers.None);
car1.LoadDataFromCultureInfo(CultureInfo.CreateSpecificCulture("ru-RU"));
car1.LoadDataFromRegionInfo(new RegionInfo("en-US"));
car1.CultureEnglishName = "Russian (United States)";
car1.CultureNativeName = "русский (США)";
car1.CurrencyNativeName = "Доллар (США)";
car1.RegionNativeName = "США";
// Register the culture.
try {
car1.Register();
}
catch (InvalidOperationException) {
// Swallow the exception: the culture already is registered.
}
// Use the custom culture.
CultureInfo ci = CultureInfo.CreateSpecificCulture("ru-US");
Thread.CurrentThread.CurrentCulture = ci;
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.Name);
Console.WriteLine("Writing System: {0}",
Thread.CurrentThread.CurrentCulture.TextInfo);
}
}
// The example displays the following output:
// Current Culture: ru-US
// Writing System: TextInfo - ru-US
I know this isn't an ideal answer, but you could manually input the list of Hebrew months, and use DateTime.Today.Month as an index into that list. Similarly, DateTime.Today.Day and .Year give integer output that you can use. Sorry, it seems a bit wrong to roll your own formatting, doesn't it?
You could still use string.format() to ensure it looks the way you want.
You can use this (I know it's not c#, but you should be able to get what I'm doing here):
Dim c As New CultureInfo("he-IL")
c.DateTimeFormat.Calendar.ToDateTime(Now.Year, Now.Month, Now.Day, Now.Hour, Now.Minute, Now.Second, Now.Millisecond).ToString("MMMM", New CultureInfo("en-GB"))
MessageBox.Show(c.DateTimeFormat.Calendar.ToDateTime(Now.Year, Now.Month, Now.Day, Now.Hour, Now.Minute, Now.Second, Now.Millisecond).ToString("MMMM", New CultureInfo("en-GB")))
But it will give you the Gregorian Calendar name (December)
piojo's suggestion to build up a dictionary object that contains the English version of the Hebrew name might work better
I do not believe that .NET has culture information that you want to use. However, you can create your own CultureInfo and modify the DateTimeFormat to suit your needs:
var cultureInfo = CultureInfo.CreateSpecificCulture("he-IL");
cultureInfo.DateTimeFormat.Calendar = new HebrewCalendar();
cultureInfo.DateTimeFormat.AbbreviatedMonthNames = new[] {
"Translation of תשרי",
"Translation of חשון",
// 11 more elements
};
cultureInfo.DateTimeFormat.AbbreviatedMonthGenitiveNames = new[] { ... };
cultureInfo.DateTimeFormat.MonthNames = new[] { ... };
cultureInfo.DateTimeFormat.MonthGenitiveNames = new[] { ... };
(Sorry for not providing the correct translations but I do not know Hebrew.)
You can then use this cultureInfo exactly as you do in your question.
If required you can also modify the day names in a similar fashion.
It is important that the calendar is set before modifying the various month and date name properties. The number of expected entries in the month name arrays changes as the calendar changes.

Set Default DateTime Format c#

Is there a way of setting or overriding the default DateTime format for an entire application. I am writing an app in C# .Net MVC 1.0 and use alot of generics and reflection. Would be much simpler if I could override the default DateTime.ToString() format to be "dd-MMM-yyyy". I do not want this format to change when the site is run on a different machine.
Edit -
Just to clarify I mean specifically calling the ToString, not some other extension function, this is because of the reflection / generated code. Would be easier to just change the ToString output.
The "default format" of a datetime is:
ShortDatePattern + ' ' + LongTimePattern
at least in the current mono implementation.
This is particularly painful in case you want to display something like 2001-02-03T04:05:06Z i.e. the date and time combined as specified in ISO 8606, but not a big problem in your case:
using System;
using System.Globalization;
using System.Threading;
namespace test {
public static class Program {
public static void Main() {
CultureInfo culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.DateTimeFormat.ShortDatePattern = "dd-MMM-yyyy";
culture.DateTimeFormat.LongTimePattern = "";
Thread.CurrentThread.CurrentCulture = culture;
Console.WriteLine(DateTime.Now);
}
}
}
This will set the default behavior of ToString on datetimes to return the format you expect.
It is dependent on your application's localization-settings. Change that accordingly to get correct format.
Otherwise have a helper-class or an extension-method which always handles your DateTime.
public static string ToMyDateTime(this DateTime dateTime) {
return dateTime.ToString("dd-MMMM-yy");
}
DateTime.ToString() combines the custom format strings returned by the ShortDatePattern and LongTimePattern properties of the DateTimeFormatInfo. You can specify these patterns in DateTimeFormatInfo.CurrentInfo.
I've never tried this my self.
If you want to be sure that your culture stays the same, just set it yourself to avoid troubles.
System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo("nl-BE");
System.Threading.Thread.CurrentThread.CurrentCulture = ci;
System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
The above example sets the culture of the thread to Belgian-Dutch.
CurrentCulture does all the date and time handling and CurrentUICulture handles UI localization like resources.
I'm not sure if this would work for a web app, but you could try to set the DateTimeFormat property for the current culture.
Check this and specially this.
Using .Net 6 put something like this in your program.cs after app.UseAuthentication()/app.UseAuthorization() and before app.MapControllerRoute(...):
var ci = new CultureInfo("en-US");
ci.DateTimeFormat.ShortDatePattern = "MM/dd/yyyy";
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture(ci),
SupportedCultures = new List<CultureInfo> { ci },
SupportedUICultures = new List<CultureInfo> { ci }
});
Here I'm changing the short date format, but you can also change currency symbol, decimal separator, etc.
You can write an ExtensionMethod like this:
public static string ToMyString(this DateTime dateTime)
{
return dateTime.ToString("needed format");
}

String.Format consider locale or not?

Is it true that String.Format works 2 ways:
if we use built-in format such as C, N, P.... it will take locale settings into account?
if we use custom format code such as #,##0.000 it will NOT take locale settings into account?
In my code, I use method like this
String.Format("{0:#.##0,000}", value);
because my country use comma as decimal separator
but the result still is: 1,234.500 as if it consider dot as decimal separator.
Please help!
You want to use CultureInfo:
value.ToString("N", new CultureInfo("vn-VN"));
Using String.Format:
String.Format(new CultureInfo("vi-VN"), "N", value);
Since you're in Hanoi (from profile), I used Vietnam's code, which is vn-VN.
This works. The formatted value is 123.456,789 which is correct per es-ES
IFormatProvider iFormatProvider = new System.Globalization.CultureInfo("es-ES");
var value = 123456.789001m;
string s = value.ToString("#,##0.000", iFormatProvider);
string s2 = string.Format(iFormatProvider, "{0:#,##0.000}", value);
FormattableString fs = $"{value:#,##0.000}";
string s3 = fs.ToString(iFormatProvider);
Note that the , and . are using a 'standard' en-US style, but .ToString() and string.Format() with a format provider does the right thing.
You should make sure your thread uses the correct culture:
Thread.CurrentThread.CurrentCulture = CultureInfo.CurrentCulture
Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture
FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)))

Categories

Resources