Enlace de fecha y hora MVC con formato de fecha incorrecto


Asp.net-MVC ahora permite el enlace implícito de objetos DateTime. Tengo una acción en las líneas de

public ActionResult DoSomething(DateTime startDate) 
{ 
... 
}

Esto convierte con éxito una cadena de una llamada ajax en una DateTime. Sin embargo, utilizamos el formato de fecha dd/MM/aaaa; MVC se está convirtiendo a MM/dd/aaaa. Por ejemplo, enviar una llamada a la acción con una cadena '09/02/2009' resulta en una fecha y hora de '02/09/2009 00: 00: 00', o el 2 de septiembre en nuestra configuración local.

No quiero enrollar mi propia carpeta modelo para el en aras de un formato de fecha. Pero parece innecesario tener que cambiar la acción para aceptar una cadena y luego usar DateTime.Analizar si MVC es capaz de hacer esto por mí.

¿Hay alguna forma de alterar el formato de fecha utilizado en la carpeta de modelos predeterminada para DateTime? De todos modos, ¿no debería utilizar la carpeta de modelos predeterminada la configuración de localización?

Author: Sam Wessel, 2009-02-09

10 answers

Acabo de encontrar la respuesta a esto con un googleo más exhaustivo:

Melvyn Harbour tiene una explicación completa de por qué MVC funciona con fechas de la manera que lo hace, y cómo puede anular esto si es necesario:

Http://weblogs.asp.net/melvynharbour/archive/2008/11/21/mvc-modelbinder-and-localization.aspx

Cuando se busca el valor a analizar, el framework se ve en un orden específico a saber:

  1. RouteData (no se muestra arriba)
  2. Cadena de consulta URI
  3. Formulario de solicitud

Sin embargo, solo el último de ellos será consciente de la cultura. Hay una muy buena razón para esto, desde una perspectiva de localización. Imagine que he escrito una aplicación web que muestra la información de vuelo de la aerolínea que publico en línea. Busco vuelos en una fecha determinada haciendo clic en un enlace para ese día (tal vez algo como http://www.melsflighttimes.com/Flights/2008-11-21 ), y luego quiero enviar ese enlace a mi colega en los estados unidos. La única manera que podríamos garantizar que ambos estaremos mirando la misma página de datos es si se utiliza la InvariantCulture. Por el contrario, si estoy usando un formulario para reservar mi vuelo, todo está sucediendo en un ciclo apretado. Los datos pueden respetar la cultura actual cuando se escriben en el formulario, y por lo tanto deben respetarlos cuando regresan del formulario.

 157
Author: Sam Wessel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-18 09:24:35

Establecería globalmente sus culturas. ModelBinder recoger eso!

  <system.web>
    <globalization uiCulture="en-AU" culture="en-AU" />

O simplemente cambia esto para esta página.
Pero globalmente en la web.config Creo que es mejor

 35
Author: Peter Gfader,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-24 12:37:42

He estado teniendo el mismo problema con el enlace de formato de fecha corta a las propiedades del modelo DateTime. Después de mirar muchos ejemplos diferentes (no solo con respecto a DateTime) armé el siguiente:

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;
            }
        }
    }
}

Para mantener la forma en que las rutas etc son regiseterd en el archivo ASAX Global también agregué una nueva clase sytatic a la carpeta App_Start de mi proyecto MVC4 llamada CustomModelBinderConfig:

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());
        }
    }
}

Luego llamo a los Registrercustommodelbinders estáticos desde mi ASASX Global Application_Start así:

protected void Application_Start()
{
    /* bla blah bla the usual stuff and then */

    CustomModelBindersConfig.RegisterCustomModelBinders();
}

Una nota importante aquí es que si escribe un valor DateTime a un hiddenfield como este:

@Html.HiddenFor(model => model.SomeDate) // a DateTime property
@Html.Hiddenfor(model => model) // a model that is of type DateTime

Hice eso y el valor real en la página estaba en el formato "MM/dd/aaaa hh:mm:ss tt" en lugar de "dd/MM/aaaa hh:mm:ss tt" como quería. Esto causó que mi validación del modelo fallara o devolviera la fecha incorrecta (obviamente intercambiando los valores de día y mes).

Después de muchos arañazos en la cabeza e intentos fallidos, la solución fue para establecer la información de la cultura para cada solicitud haciendo esto en el 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;
}

No funcionará si lo pegas en Application_Start o incluso Session_Start ya que eso lo asigna al hilo actual para la sesión. Como bien sabes, las aplicaciones web son apátridas, por lo que el hilo que atendió su solicitud anteriormente es el mismo hilo que atiende su solicitud actual, por lo tanto, su información cultural ha ido al gran GC en el cielo digital.

Gracias a: Ivan Zlatev - http://ivanz.com/2010/11/03/custom-model-binding-using-imodelbinder-in-asp-net-mvc-two-gotchas/

Garik - https://stackoverflow.com/a/2468447/578208

Dmitry - https://stackoverflow.com/a/11903896/578208

 28
Author: WernerVA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:38

Va a ser ligeramente diferente en MVC 3.

Supongamos que tenemos un controlador y una vista con el método Get

public ActionResult DoSomething(DateTime dateTime)
{
    return View();
}

Deberíamos añadir 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
}

Y el comando en Application_Start () de Global.asax

ModelBinders.Binders.Add(typeof(DateTime), new DateTimeBinder());
 13
Author: Dmitry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-10 14:35:21

También vale la pena señalar que incluso sin crear su propio modelo de carpeta múltiples formatos diferentes pueden ser parsable.

Por ejemplo en los EE.UU. todas las siguientes cadenas son equivalentes y automáticamente se enlazan a el mismo valor DateTime:

/ company / press / may%2001% 202008

/ company / press / 2008-05-01

/ company / press / 05-01-2008

Recomiendo encarecidamente usar aaaa-mm-dd porque es mucho más portátil. Realmente no quiero lidiar con el manejo de múltiples formatos localizados. Si alguien reserva un vuelo el 1 de mayo en lugar del 5 de enero, ¡tendrá grandes problemas!

NB: No estoy claro exactamente si aaaa-mm-dd se analiza universalmente en todas las culturas, por lo que tal vez alguien que sabe puede agregar un comentario.

 8
Author: Simon_Weaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-15 03:40:59

Establecí la siguiente configuración en mi MVC4 y funciona como un encanto

<globalization uiCulture="auto" culture="auto" />
 5
Author: JeeShen Lee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-10 10:40:00

Intenta usar toISOString(). Devuelve cadena en formato ISO8601.

Método GET

Javascript

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

C #

[HttpGet]
public JsonResult DoGet(DateTime date)
{
    return Json(date.ToString(), JsonRequestBehavior.AllowGet);
}

Método POST

Javascript

$.post('/example/do', { date: date.toISOString() }, function (result) {
    console.log(result);
});

C #

[HttpPost]
public JsonResult Do(DateTime date)
{
     return Json(date.ToString());
}
 4
Author: rnofenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-29 16:30:16
  public class DateTimeFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Request.RequestType == "GET")
        {

            foreach (var parameter in filterContext.ActionParameters)
            {
                var properties = parameter.Value.GetType().GetProperties();

                foreach (var property in properties)
                {
                    Type type = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;

                    if (property.PropertyType == typeof(System.DateTime) || property.PropertyType == typeof(DateTime?))
                    {
                        DateTime dateTime;

                        if (DateTime.TryParse(filterContext.HttpContext.Request.QueryString[property.Name], CultureInfo.CurrentUICulture, DateTimeStyles.None, out dateTime))
                            property.SetValue(parameter.Value, dateTime,null);
                    }
                }

            }
        }
    }
}
 1
Author: tobias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-30 15:24:04
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    var str = controllerContext.HttpContext.Request.QueryString[bindingContext.ModelName];
    if (string.IsNullOrEmpty(str)) return null;
    var date = DateTime.ParseExact(str, "dd.MM.yyyy", null);
    return date;
}
 1
Author: Teth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-08 03:44:51

Establezco CurrentCulture y CurrentUICulture mi controlador base personalizado

    protected override void Initialize(RequestContext requestContext)
    {
        base.Initialize(requestContext);

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
    }
 0
Author: Korayem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-27 21:56:22