Asp.net mvc 日期格式不正确的MVC日期时间绑定

Asp.net mvc 日期格式不正确的MVC日期时间绑定,asp.net-mvc,datetime,localization,formatting,model-binders,Asp.net Mvc,Datetime,Localization,Formatting,Model Binders,Asp.net-MVC现在允许隐式绑定DateTime对象。我有一项行动是按照 public ActionResult DoSomething(DateTime startDate) { ... } 这将成功地将ajax调用中的字符串转换为DateTime。但是,我们使用日期格式dd/MM/yyyy;MVC正在转换为MM/dd/yyyy。 例如,使用字符串“09/02/2009”提交对操作的调用会导致日期时间为“02/09/2009 00:00:00”,或在本地设置中为9月2日 我不想为了

Asp.net-MVC现在允许隐式绑定DateTime对象。我有一项行动是按照

public ActionResult DoSomething(DateTime startDate) 
{ 
... 
}
这将成功地将ajax调用中的字符串转换为DateTime。但是,我们使用日期格式dd/MM/yyyy;MVC正在转换为MM/dd/yyyy。 例如,使用字符串“09/02/2009”提交对操作的调用会导致日期时间为“02/09/2009 00:00:00”,或在本地设置中为9月2日

我不想为了日期格式而滚动我自己的模型活页夹。但是,如果MVC能够为我做到这一点,那么似乎不必更改操作以接受字符串,然后使用DateTime.Parse


有没有办法改变DateTime默认模型活页夹中使用的日期格式?默认模型绑定器不应该使用您的本地化设置吗?

我刚刚通过一些更详尽的谷歌搜索找到了答案:

Melvyn Harbor详细解释了为什么MVC会以这种方式处理日期,以及您如何在必要时覆盖它:

在查找要分析的值时,框架按特定顺序查找,即:

  • 路由数据(上面未显示)
  • URI查询字符串
  • 申请表
  • 然而,只有最后一种才具有文化意识。从本地化的角度来看,这有一个很好的理由。想象一下,我已经编写了一个web应用程序,显示我在线发布的航班信息。我通过点击某一天的链接(可能是类似的链接)查找某一天的航班,然后想通过电子邮件将该链接发送给我在美国的同事。我们能够保证我们都会看到同一页数据的唯一方法是使用不变量文化。相比之下,如果我使用表单预订航班,那么一切都是在一个紧张的循环中发生的。数据写入表单时可以尊重CurrentCulture,因此从表单返回时需要尊重它


    还值得注意的是,即使不创建自己的模型绑定器,也可以使用多种不同的格式

    例如,在美国,以下所有字符串都是等效的,并自动绑定到相同的日期时间值:

    /公司/新闻/2001年5月%202008

    /公司/出版社/2008-05-01

    /公司/新闻/05-01-2008

    我强烈建议使用yyyy-mm-dd,因为它更便于携带。您确实不想处理多个本地化格式。如果有人在5月1日而不是1月5日预订航班,你会遇到大问题


    注:我不清楚yyyy-mm-dd是否在所有文化中都被普遍解析,因此可能有人知道可以添加注释。

    我会全局设置您的文化。把它捡起来

      <system.web>
        <globalization uiCulture="en-AU" culture="en-AU" />
    
    
    
    或者您只需更改此页面的内容。

    但是在全球范围内,我认为web.config更好

    在MVC 3中会略有不同

    假设我们有一个控制器和一个带有Get方法的视图

    public ActionResult DoSomething(DateTime dateTime)
    {
        return View();
    }
    
    我们应该添加ModelBinder

    public class DateTimeBinder : IModelBinder
    {
        #region IModelBinder Members
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            DateTime dateTime;
            if (DateTime.TryParse(controllerContext.HttpContext.Request.QueryString["dateTime"], CultureInfo.GetCultureInfo("en-GB"), DateTimeStyles.None, out dateTime))
                return dateTime;
            //else
            return new DateTime();//or another appropriate default ;
        }
        #endregion
    }
    
    以及Global.asax的应用程序_Start()中的命令

    ModelBinders.Binders.Add(typeof(DateTime), new DateTimeBinder());
    

    我在MVC4上设置了下面的配置,它就像一个符咒

    <globalization uiCulture="auto" culture="auto" />
    

    我在将短日期格式绑定到日期时间模型属性时遇到了同样的问题。在查看了许多不同的示例(不仅仅是关于日期时间)后,我总结了以下内容:

    using System;
    using System.Globalization;
    using System.Web.Mvc;
    
    namespace YourNamespaceHere
    {
        public class CustomDateBinder : IModelBinder
        {
            public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                if (controllerContext == null)
                    throw new ArgumentNullException("controllerContext", "controllerContext is null.");
                if (bindingContext == null)
                    throw new ArgumentNullException("bindingContext", "bindingContext is null.");
    
                var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    
                if (value == null)
                    throw new ArgumentNullException(bindingContext.ModelName);
    
                CultureInfo cultureInf = (CultureInfo)CultureInfo.CurrentCulture.Clone();
                cultureInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
    
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
    
                try
                {
                    var date = value.ConvertTo(typeof(DateTime), cultureInf);
    
                    return date;
                }
                catch (Exception ex)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
                    return null;
                }
            }
        }
    
        public class NullableCustomDateBinder : IModelBinder
        {
            public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                if (controllerContext == null)
                    throw new ArgumentNullException("controllerContext", "controllerContext is null.");
                if (bindingContext == null)
                    throw new ArgumentNullException("bindingContext", "bindingContext is null.");
    
                var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    
                if (value == null) return null;
    
                CultureInfo cultureInf = (CultureInfo)CultureInfo.CurrentCulture.Clone();
                cultureInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
    
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
    
                try
                {
                    var date = value.ConvertTo(typeof(DateTime), cultureInf);
    
                    return date;
                }
                catch (Exception ex)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
                    return null;
                }
            }
        }
    }
    
    为了保持路由等在全局ASAX文件中注册的方式,我还向MVC4项目的App_Start文件夹添加了一个名为CustomModelBinderConfig的新sytatic类:

    using System;
    using System.Web.Mvc;
    
    namespace YourNamespaceHere
    {
        public static class CustomModelBindersConfig
        {
            public static void RegisterCustomModelBinders()
            {
                ModelBinders.Binders.Add(typeof(DateTime), new CustomModelBinders.CustomDateBinder());
                ModelBinders.Binders.Add(typeof(DateTime?), new CustomModelBinders.NullableCustomDateBinder());
            }
        }
    }
    
    然后,我只需从我的全局ASASX应用程序中调用静态寄存器CustomModelbinders,如下所示:

    protected void Application_Start()
    {
        /* bla blah bla the usual stuff and then */
    
        CustomModelBindersConfig.RegisterCustomModelBinders();
    }
    
    @Html.HiddenFor(model => model.SomeDate) // a DateTime property
    @Html.Hiddenfor(model => model) // a model that is of type DateTime
    
    这里需要注意的一点是,如果将DateTime值写入hiddenfield,如下所示:

    protected void Application_Start()
    {
        /* bla blah bla the usual stuff and then */
    
        CustomModelBindersConfig.RegisterCustomModelBinders();
    }
    
    @Html.HiddenFor(model => model.SomeDate) // a DateTime property
    @Html.Hiddenfor(model => model) // a model that is of type DateTime
    
    我这样做了,页面上的实际值是“MM/dd/yyyy hh:MM:ss tt”格式,而不是我想要的“dd/MM/yyyy hh:MM:ss tt”。这导致我的模型验证要么失败,要么返回错误的日期(显然交换了日期和月份值)

    在经历了大量的挠头和失败的尝试之后,解决方案是通过在Global.ASAX中执行以下操作来为每个请求设置区域性信息:

    protected void Application_BeginRequest()
    {
        CultureInfo cInf = new CultureInfo("en-ZA", false);  
        // NOTE: change the culture name en-ZA to whatever culture suits your needs
    
        cInf.DateTimeFormat.DateSeparator = "/";
        cInf.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
        cInf.DateTimeFormat.LongDatePattern = "dd/MM/yyyy hh:mm:ss tt";
    
        System.Threading.Thread.CurrentThread.CurrentCulture = cInf;
        System.Threading.Thread.CurrentThread.CurrentUICulture = cInf;
    }
    
    如果您将它粘贴到应用程序启动或会话启动中,它将不起作用,因为这样会将它分配给会话的当前线程。正如您所知,web应用程序是无状态的,因此以前为您的请求提供服务的线程与为您当前的请求提供服务的线程不同,因此您的区域性信息已在数字天空中进入了伟大的GC

    多谢各位: 伊万·兹拉捷夫-

    加里克-

    Dmitry-

    尝试使用toISOString()。它以ISO8601格式返回字符串

    获取方法

    javascript

    $.get('/example/doGet?date=' + new Date().toISOString(), function (result) {
        console.log(result);
    });
    
    $.post('/example/do', { date: date.toISOString() }, function (result) {
        console.log(result);
    });
    
    c#

    POST方法

    javascript

    $.get('/example/doGet?date=' + new Date().toISOString(), function (result) {
        console.log(result);
    });
    
    $.post('/example/do', { date: date.toISOString() }, function (result) {
        console.log(result);
    });
    
    c#


    我设置了
    CurrentCulture
    CurrentUICulture
    我的自定义基本控制器

        protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
    
            Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
        }
    

    行。该功能在发布问题后48小时内被禁用。我强烈不同意从技术上说这是正确的。模型绑定器的行为应始终与POST和GET相同。如果不变文化是获取的方式,那么也可以将其用于POST。根据http动词更改行为是没有意义的。我有一个问题,我们的网站位于另一个国家,它需要
    MM/dd/yyyy
    格式,否则它显示验证错误
    字段BeginDate必须是日期。
    ,我如何使服务器接受
    dd/MM/yyyy
    格式?URL参数应该是明确的,比如使用ISO标准格式。那么区域性设置就无关紧要了。这提供了解释原因的链接,但实际上并没有提供解决此问题的任何最简单的方法(例如通过从脚本发布ISO日期时间字符串),这种方式总是有效的,我们不必关心在服务器上设置特定的区域性,也不必确保服务器和客户端之间的日期时间格式是相同的。d