Textbox for DateTime wrong format - c#

I know this is one of the most frequently asked questions.
I had the solution to this but my current project is driving me nuts.
I use the exact same code and still the result is different.
This is the code I normally use to format my dates:
#Html.TextBoxFor(m => m.DateOfAgenda, "{0:dd/MM/yyyy}")
Normally this should result in 07/10/2014 but for some reason it results in 07-10-2014
When I test it in another project the code above works as expected.
As a test I compared the results of the follow lines:
#Html.TextBoxFor(m => m.DateOfAgenda, "{0:dd/MM/yyyy}")
/* result: 07-10-2014*/
#Html.TextBoxFor(m => m.DateOfAgenda)
/* result: 7-10-2014 00:00:00*/
So my code seems to work partially only the '-' won't be replaced by '/'
Does somebody know how to handle this once and for all?
EDIT
I have custom code setting the Culture.
It uses the route to set it to a specific culture (default is 'nl')
When I put the code below in comments everything seems to work.
But I need this part to load my resources (label text, errors, ...).
var language = handler.RequestContext.RouteData.Values["language"];
if (language != null)
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language.ToString());
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language.ToString());
}
To be more specific this line breaks the format
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language.ToString());
Does anybody know why? I would expect that {0:dd/MM/yyyy} has priority because it is explicitly set.
Funny part is that the / is just translated to -.
When I use {0:dd//MM//yyyy} it results in 19--10--2014.
EDIT
Sorry for my late response but I couldn't find the time to try this out.
So basically the problem was the culture and my format settings.
#Html.TextBoxFor(m => m.DateOfAgenda, "{0:dd/MM/yyyy}")
The '/' still gets replaced by the divider specified by your culture.
My culture was set to 'nl' but by default this results in 'nl-nl' where they use '-' as date separator. I live in Belgium 'nl-be' and here we use '/'.
The could have set my culture or change the format.
The code below did the trick.
#Html.TextBoxFor(m => m.DateOfAgenda, "{0:dd'/'MM'/'yyyy}")

I'm not that familiar with ASP.NET MVC, but if you don't specify a format, your current culture's DateTimeFormat is used. Also, / is a special format specifier in .NET which means "replace me with the current DateTimeFormats date-separator which seems to be -.
So you should provide CultureInfo.InvariantCulture or mask the format specifier by using \\/instead:
#Html.TextBoxFor(m => m.DateOfAgenda, "{0:dd\\/MM\\/yyyy}")
or by using the character literal '/':
#Html.TextBoxFor(m => m.DateOfAgenda, "{0:dd'/'MM'/'yyyy}")
Read: The "/" Custom Format Specifier

This appears to be by design. TextBoxFor sets the value as per the following code snippet
string attemptedValue = (string)htmlHelper.GetModelStateValue(fullName, typeof(string));
tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(fullName, format) : valueParameter), isExplicitValue);
which calls the EvalString method of HtmlHelper
internal string EvalString(string key, string format)
{
return Convert.ToString(ViewData.Eval(key, format), CultureInfo.CurrentCulture);
}
which calls the Eval method of ViewDataDictionary
public string Eval(string expression, string format)
{
object value = Eval(expression);
return FormatValueInternal(value, format);
}
internal static string FormatValueInternal(object value, string format)
{
....
return String.Format(CultureInfo.CurrentCulture, format, value);
}
So the value uses the format of the current culture. I presume this is because the DefaultModelBinder use the current culture info to parse the string representation of the date back to a DateTime (if you were able to override it, it would not bind unless you created a custom model binder.

View Page
#Html.TextBoxFor(m => m.DateOfAgenda, new { Value = Model.DateOfAgenda.ToString("dd/MM/yyyy")});

Model page
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime DateOfAgenda{ get; set;}
View Page
#Html.EditorFor(model => model.DateOfAgenda)

Related

Handling logic and constants in the View

I have a date that gets displayed on my View that shows the last date a user logged in. They may have never done so. So it's passed as a nullable DateTime.
On the UI, I display it like this:
<td>#(u.LastVisit != null ? u.LastVisit.Value.ToString("dd-MMM-yyyy") : "Not yet")</td>
But I have a few issues with this and think it might be bad practice.
Firstly, the view now has logic. (If null, show "Not Yet", else show the date). The View also dictates the date format. That format is already stored as a constant in a Constants file, accessible from my controller. And the text "Not Yet" should probably be a constant as well.
The only way I can see around this, is to return a String to the UI, and move that logic to the controller. But is that the right way to do this?
You can apply a [DisplayFormat] attribute to the property and set the DataFormatString and NullDisplayText properties, for example
[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}", NullDisplayText = "Not yet")]
public DateTime? LastVisit { get; set; }
If you have already defined some constants for the format then you can use (for example) DataFormatString = yourAssembly.Constants.DateFormat where DateFormat is defined as
public const string DateFormat = "{0:dd-MMM-yyyy}";
and in the view use DisplayFor()
#foreach(var u in Model)
{
#Html.DisplayFor(m => u.LastVisit)
}

Change display format number decimal separator

I have the following float number : -95.83334
this is in my view model:
[DisplayFormat(DataFormatString = "{0:#.##}")]
public float? mx { get; set; }
this is in my view
#Html.HiddenFor(model => model.mx)
this is the generated html
<input data-val="true" id="mx" name="mx" type="hidden" value="-95,83334">
and this is the desired html
<input data-val="true" id="mx" name="mx" type="hidden" value="-95.83334">
so the question is, which is the best way to change the decimal separator for this hidden input? without alter the the rest of my project
DisplayFormat is used when you use Html.DisplayFor. And, it's only for formatting what's supposed to be displayed on the view. If you want to change the format of decimal numbers in general, you'll need to use a different culture.
Finally, this was the solution for me
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
#Html.HiddenFor(model => model.mx)
adding the line
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
before my hidden solved the problem. thanks for the ideas and guides!
#Html.HiddenFor(model => model.mx.ToString(new CultureInfo("en-us")));
Edit:
Sorry for the brief answer. I think it would have been useful if it had worked, unfortunately I missed something important in your code.
Your issue is a localization problem. I'm guessing your machine is running with a European culture. (Just noticed your comment about being it set as Spanish)
ToString() has been overloaded for some of the basic types, float included. One of these overloads accepts an IFormatProvider which CultureInfo implements. By passing a CultureInfo using the culture code for United States English, you can ensure the dot will be used instead of the comma as the decimal separator.
What I missed is that mx is a float?, which is short for Nullable. Nullable does not overload ToString in the same way, so you have a couple of alternatives.
If you are using C#6, you can use the null check operator to convert your float? back to a float. You could then use the ToString overload:
#Html.HiddenFor(model => model.mx?.ToString(CultureInfo.GetCultureInfo("en-us")));
Alternatively, you can use the String.Format overload, which accepts both a format string and an IFormatProvider:
#Html.HiddenFor(model => String.Format(CultureInfo.GetCultureInfo("en-us"), "{0:#.##}", model.mx));
I did not want to suggest changing the culture of your thread because this stood out in your question "without alter the the rest of my project" which I, perhaps mistakenly, assumed to mean you did not want to change the formatting of other components in your application. Changing the default thread culture could have a larger impact than you anticipate.
Edit 2:
Here is my attempt at an extension overload accepting an IFormatProvider. This was just an experiment and shouldn't be used in production... I'm including it purely for interest sake.
public static class HtmlExtensions
{
public static IHtmlString HiddenFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IFormatProvider formatter)
{
var value = expression.Compile().Invoke(helper.ViewData.Model);
var modelMetadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
var property = typeof(TModel).GetProperty(modelMetadata.PropertyName);
var attribute = property.GetCustomAttributes(typeof(DisplayFormatAttribute), false).SingleOrDefault() as DisplayFormatAttribute;
var displayValue = String.Format(formatter, attribute?.DataFormatString ?? "{0}", value);
TagBuilder tagBuilder = new TagBuilder("input");
tagBuilder.MergeAttribute("type", "hidden");
tagBuilder.MergeAttribute("value", displayValue);
return MvcHtmlString.Create(tagBuilder.ToString());
}
}
Use it like this
#Html.HiddenFor(mode => mode.myNumber, System.Globalization.CultureInfo.GetCultureInfo("en-us"))

Convert DateTime to string using another string as a template

I have a string that contains a date & time in some format. For example:
13:53:56 20.08.2014
This string is parsed from a file that user uploads to my service. The exact date & time format is not known. It can change to pretty much any date & time format you know. I do not have a list a expected formats or anything like that.
I want to develop an algorithm that somehow extracts the format from the initial string and applies it to, say, DateTime.Now.
Is there any way to do this simply and elegantly?
If you know the list of expected formats, then define them and use DateTime.TryParseExact() to find out the matching format of your input string. Once you have the matching format, you can simply use the matching format with DateTime.Now.ToString(format).
If this is a web application, perhaps you can "cheat a bit" by sniffing the user's regional settings before they input the string.
The MSDN article "How to: Display Localized Date and Time Information to Web Users" has useful information.
Inspired by a good suggestion by Mani, I've created the following extension method for my needs:
public static bool TryFormatLike(this DateTime dateTime, string another, out string result)
{
var allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures | CultureTypes.UserCustomCulture | CultureTypes.ReplacementCultures);
foreach (var culture in allCultures)
{
var allPatterns = culture.DateTimeFormat.GetAllDateTimePatterns();
foreach (var pattern in allPatterns)
{
DateTime parsedAnother;
if (DateTime.TryParseExact(another, pattern, culture.DateTimeFormat, DateTimeStyles.AllowWhiteSpaces, out parsedAnother))
{
result = dateTime.ToString(pattern);
return true;
}
}
}
result = string.Empty;
return false;
}
You can use it like that:
string formattedNow;
if (DateTime.Now.TryFormatLike("13.02.2015 16:14:43", out formattedNow))
{
Console.WriteLine(formattedNow);
}
This will print
10.03.2015 23:37:08
Unfortunately, some date & time formats cannot be parsed by all patters in all cultures (for instance, string 16:14:43 13.02.2015 will not be parsed).
Anyway, thank you for your comments & answers. Maybe this method will be helpful to someone.

how to display plain string as date mvc

In my mvc application I have stored my date in string format. eg: 10212013
But I would like to display that sting as a date in my UI eg: 10/21/2013
How to archive this?? Is it possible to user DisplayFormat for this purpose.
EDIT
This is what I need to do.
#Html.DisplayFor(model => DailyTransaction.MyDate)
Datatype of MyDate is string so this will display as 10212013
But I need to display this as 10/21/2013
can I use string format inside the view of MVC project
I tried to use the following and that is also did not work for me.
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
public string MyDate{ get; set; }
Try creating a custom DisplayFormatAttribute that will format the string in the correct format. See this How to make configurable DisplayFormat attribute
EDIT: After looking at your question again you could look at using an editor template to display the data: See this: http://blogs.msdn.com/b/nunos/archive/2010/02/08/quick-tips-about-asp-net-mvc-editor-templates.aspx
Use DateTime.ToString() like;
YourDateTime.ToString("MM/dd/yyyy", CultureInfo.InvariantCulture);
For example;
DateTime d = DateTime.Today;
Console.WriteLine(d.ToString("MM/yy/yyyy", CultureInfo.InvariantCulture));
Output will be;
10/21/2013
Here a DEMO.
As an alternative, you can use DisplayFormatAttribute.DataFormatString like;
[DisplayFormat(DataFormatString="{0:MM/yy/yyyy}")]
yeah you just have to use insert function. here is the example
string dateValue = "10212013";
string dateFormat = x.Insert(2, "/");
dateFormat = dateFormat.Insert(5, "/");
thats all...
If you are sure about the saved format of the date you could use Substring() and Format() methods as below:
string.Format("{0}/{1}/{2}", myStringDate.Substring(0,2),
myStringDate.Substring(2,2),
myStringDate.Substring(4))
You can apply this to your Class and here is a demo;
public class myModelClass
{
private string _MyDate;
public string MyDate
{
get {
return string.Format("{0}/{1}/{2}", _MyDate.Substring(0,2),
_MyDate.Substring(2,2),
_MyDate.Substring(4)); }
set { _MyDate = value; }
}
}
You can create custom templates for various data types that are specific to your requirements.
To create a custom template create a new file in /Views/Shared/DisplayTemplates - Call it StringToDate.cshtml. The name is important and is used in the function call below.
Next, in the file add the code to convert the string to a date format as you require. The simplest solution is to insert the / characters.
#model string
if (Model != null && Model.Length == 8)
{
#(Model.Insert(2,"/").Insert(5,"/"))
} else {
#("Err")
}
Add the above to the file and save it. The else part simply outputs an error if the basic format checks fail.
Next in your view, where ever you need to display this value. Simply use
#Html.DisplayFor(model => model.StringDate, "StringToDate")

How to change display format of long variable?

I have a variable of type Long i.e.
long quantity=1000;
I want to display it like 1,000 in Grid (Must need commas)
How do i achieve this?
I am using a Telerik Grid and I am binding the data as follows:
columns.Bound(tempProductList => tempProductList.tempProductListQuantity) .Title("Quantity")
Here you have a list of all the standard numeric formats. I think "N" is the one you want.
long l = 1234;
string s = l.ToString("N0"); //gives "1,234"
The "0" after the format specifier is the number of desired decimal places (usually 2 by default).
Note that this version is culture-sensitive, i.e., in my country, we use dots (".") as thousand separators, so the actual returned value will be "1.234" instead of the "1,234". If this is desired behaviour, just leave it as is, but if you need to use commas always, then you should specify a culture as a parameter to the ToString method, like
l.ToString("N0", CultureInfo.InvariantCulture); //always return "1,234"
You could create a Custom Culture that will allow you to specify the thousand separator.
From this article:
//Create first the format provider the String.Format
//will use to format our string
CultureInfo cultureToUse = new CultureInfo("fi-FI");
Console.WriteLine("Using the following CultureInfor " +
cultureToUse.Name);
//Now practice some decimal numbers
//Here we override the culture specific formattings
cultureToUse.NumberFormat.CurrencyDecimalDigits = 3;
cultureToUse.NumberFormat.NumberDecimalDigits = 3;
cultureToUse.NumberFormat.NumberGroupSeparator = " ";
cultureToUse.NumberFormat.CurrencySymbol = "euro";
cultureToUse.NumberFormat.NumberDecimalSeparator = ",";
Next you would need to use this culture when formatting the numbers.
You could do the formattin gby hand but you could also assign the culture to the Current(UI)Culture property of the current thread.
If you want to consider the international point of view, there will not be always commas before the decimal part. ToString function will give you what you want.
(1000.0).ToString("N",new CultureInfo("en-US")) = 1,000.00
(1000.0).ToString("N",new CultureInfo("is-IS")) = 1.000,00

Categories

Resources