गलत तारीख प्रारूप के साथ एमवीसी डेटटाइम बाइंडिंग


132

Asp.net-MVC अब DateTime वस्तुओं के निहित बंधन के लिए अनुमति देता है। की तर्ज पर मेरे पास एक कार्रवाई है

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

यह सफलतापूर्वक एक स्ट्रिंग को एक अजाक्स कॉल से डेटटाइम में परिवर्तित करता है। हालाँकि, हम दिनांक प्रारूप dd / MM / yyyy का उपयोग करते हैं; MVC MM / dd / yyyy में परिवर्तित हो रहा है। उदाहरण के लिए, '02 / 09/2009 00:00:00 ', या हमारी स्थानीय सेटिंग में 2 सितंबर की तारीख के परिणाम के साथ एक स्ट्रिंग '09 / 02/2009' के परिणाम के लिए कॉल सबमिट करना।

मैं तिथि प्रारूप के लिए अपने स्वयं के मॉडल बाइंडर को रोल नहीं करना चाहता। लेकिन स्ट्रिंग को स्वीकार करने के लिए कार्रवाई को बदलना और उसके बाद DateTime.Parse का उपयोग करना अनावश्यक है, यदि MVC मेरे साथ ऐसा करने में सक्षम है।

क्या डेटटाइम के लिए डिफ़ॉल्ट मॉडल बाइंडर में उपयोग किए जाने वाले दिनांक प्रारूप को बदलने का कोई तरीका है? वैसे भी डिफ़ॉल्ट मॉडल बाइंडर को आपके स्थानीयकरण सेटिंग का उपयोग नहीं करना चाहिए?


अरे .. बस अपने सिस्टम की तारीख प्रारूप को बदलें- DD / MM / yyyy to MM / DD / yyyy और इसे किया .. मुझे भी यही समस्या है, मैंने इसे सिस्टम तिथि प्रारूप बदलकर हल किया।
केनी

@ इब्न अगर एप्लीकेशन ग्लोबल है और हो सकता है कि हर एक में एक ही तारीख का फॉर्मेट न हो, तो आप ऐसा कैसे कर सकते हैं? , आप जाने के लिए और हर एक को बदलने के लिए नहीं लगता है कि दिनांक स्वरूप ..
रवि मेहता

इनमें से कोई भी उत्तर मेरी मदद नहीं कर रहा है। प्रपत्र को स्थानीयकृत करने की आवश्यकता है। कुछ उपयोगकर्ताओं के पास एक तरीका हो सकता है, दूसरे अन्य तरीके से। Web.config में कुछ सेट करना। या Global.asax मदद करने वाला नहीं है। मैं एक बेहतर उत्तर की खोज करता रहूँगा, लेकिन एक तरीका यह होगा कि मैं स्ट्रिंग के रूप में तारीख से निपटूं जब तक कि मैं c # पर वापस नहीं आता।
एस्ट्रोस्टेव

जवाबों:


164

मैंने अभी कुछ अधिक संपूर्ण googling के साथ इसका उत्तर पाया है:

मेल्विन हार्बर ने इस बात की गहन व्याख्या की है कि एमवीसी तारीखों के साथ काम करता है जिस तरह से यह करता है, और यदि आवश्यक हो तो आप इसे कैसे ओवरराइड कर सकते हैं:

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

जब पार्स करने के लिए मूल्य की तलाश है, तो फ्रेमवर्क एक विशिष्ट क्रम में दिखता है:

  1. रूटडेटा (ऊपर नहीं दिखाया गया)
  2. URI क्वेरी स्ट्रिंग
  3. अनुरोध प्रपत्र

हालांकि इनमें से अंतिम केवल संस्कृति के बारे में पता होगा। स्थानीयकरण के दृष्टिकोण से, इसका एक बहुत अच्छा कारण है। कल्पना कीजिए कि मैंने एक वेब एप्लीकेशन लिखी है जिसमें एयरलाइन की उड़ान की जानकारी है जो मैं ऑनलाइन प्रकाशित करता हूं। मैं उस दिन के लिए एक लिंक पर क्लिक करके कुछ निश्चित तारीखों में उड़ानों को देखता हूं (शायद कुछ ऐसा http://www.melsflighttimes.com/Flights/2008-11-21 ), और फिर उस लिंक को अपने सहयोगी को ईमेल करना चाहता हूं। अमेरिका। एकमात्र तरीका जो हम गारंटी दे सकते हैं कि हम दोनों डेटा के एक ही पृष्ठ पर देख रहे हैं, अगर InvariantCulture का उपयोग किया जाता है। इसके विपरीत, अगर मैं अपनी उड़ान बुक करने के लिए एक फॉर्म का उपयोग कर रहा हूं, तो सब कुछ एक तंग चक्र में हो रहा है। प्रपत्र में लिखे जाने पर डेटा करंटकल्चर का सम्मान कर सकता है, और इसलिए फॉर्म से वापस आने पर इसका सम्मान करने की आवश्यकता होती है।


करूँगा। प्रश्न पोस्ट करने के 48 घंटे बाद तक कार्यक्षमता अक्षम है।
सैम वेसेल

43
मैं दृढ़ता से असहमत हूं कि तकनीकी रूप से यह सही है। मॉडल बाइंडर को हमेशा POST और GET के साथ समान व्यवहार करना चाहिए। यदि अपरिवर्तनीय संस्कृति GET के लिए जाने का रास्ता है, तो इसे POST के लिए भी बनाएं। Http क्रिया के आधार पर व्यवहार को बदलना गैर-समझदारी है।
बार्ट कैलिक्सो

मेरे पास एक प्रश्न है, हमारी वेबसाइट दूसरे देश में होस्ट की गई है, इसे MM/dd/yyyyप्रारूप की आवश्यकता है और यह सत्यापन त्रुटि दिखाता है The field BeginDate must be a date., मैं dd/MM/yyyyप्रारूप को स्वीकार करने के लिए कैसे गंभीर बना सकता हूं ?
शैजूट

URL पैरामीटर असंदिग्ध होना चाहिए, जैसे ISO मानक स्वरूपण का उपयोग करना। तब संस्कृति सेटिंग्स कोई फर्क नहीं पड़ता।
nforss

यह कारण बताते हुए लिंक देता है लेकिन वास्तव में इस मुद्दे पर कोई आसान समाधान प्रदान नहीं करता है (जैसे कि स्क्रिप्ट से आईएसओ डेटाइम स्ट्रिंग पोस्ट करके), यह तरीका हमेशा काम करता है और हमें एक विशिष्ट संस्कृति को स्थापित करने के बारे में परवाह नहीं है सर्वर या सुनिश्चित करें कि सर्वर और क्लाइंट के बीच डेटाटाइम प्रारूप समान है।
होपलेस

36

मैं विश्व स्तर पर आपकी संस्कृतियों को स्थापित करूंगा। ModelBinder उठाओ कि!

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

या आप इस पृष्ठ के लिए इसे बदल दें।
लेकिन वैश्विक रूप से web.config में मुझे लगता है कि बेहतर है


27
मेरे लिए नहीं था। यदि मैं 23/10/2010 पास करता हूं तो तारीख अभी भी अशक्त है।
गोनैले

मुझे लगता है कि यह सबसे आसान उपाय है। मेरे लिए यह सभी Date.ToString () में स्वरूप बदलता है। मुझे लगता है कि यह बाध्यकारी के साथ भी काम करेगा, लेकिन जांच नहीं की, क्षमा करें :-(
msa.im

1
मेरे पास dd / MM / yyyy के लिए मेरे देव सर्वर सेटफॉर्मैट हैं। मॉडलबाइंडर ने MM / dd / yyyy प्रारूप का उपयोग किया है। प्रारूप को web.config में dd / MM / yyyy पर सेट करने से अब मॉडर्बाइंडर को यूरोपीय प्रारूप का उपयोग करने के लिए मजबूर किया जाता है। मेरी राय में इसे सर्वर की दिनांक सेटिंग्स का उपयोग करना चाहिए। वैसे भी आपने मेरी समस्या हल कर दी।
केरेल

यह मेरे लिए पूरी तरह से काम किया ... किसी तरह यह अजीब लगा, हालांकि मुझे पता है कि मेरा एप्लिकेशन सर्वर यूके में यूके ओएस चला रहा है ...: /
टैल्मरीस 24'13

MVC4 में पूरी तरह से काम किया Azure वेबसाइटों पर चल रहा है
Matty Bear

31

मैं शॉर्ट डेट फॉर्मेट बाइंडिंग टू डेटटाइम मॉडल प्रॉपर्टीज के साथ एक ही मुद्दा रहा है कई अलग-अलग उदाहरणों को देखने के बाद (न केवल डेटाइम के विषय में) मैंने फोलविंग को एक साथ रखा:

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

ग्लोबल एएसएएक्स फ़ाइल में मार्ग आदि जिस तरह से रजिस्ट्रर्ड हैं, उसके साथ रखने के लिए मैंने अपने MVC4 प्रोजेक्ट के Custom_odelBinderConfig नाम के App_Start फ़ोल्डर में एक नया साइटेटिक क्लास भी जोड़ा है:

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 Application_Start से स्थिर RegisterCustomModelBinders कॉल करता हूं:

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

यदि आप इसे Application_Start या Session_Start में चिपकाते हैं तो यह काम नहीं करेगा क्योंकि यह सत्र के लिए वर्तमान थ्रेड को असाइन करता है। जैसा कि आप अच्छी तरह से जानते हैं, वेब एप्लिकेशन स्टेटलेस होते हैं, इसलिए जो धागा आपके अनुरोध को सेवित करता है, वह वही धागा होता है जो आपके वर्तमान अनुरोध को प्रदान करता है इसलिए आपकी संस्कृति की जानकारी डिजिटल आकाश में महान GC में चली गई है।

धन्यवाद पर जाएं: इवान ज़्लाटेव - http://ivanz.com/2010/11/03/custom-model-binding-using-imodelbinder-in-asp-net-mvc-two-gotchas/

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

दिमित्री - https://stackoverflow.com/a/11903896/578208


13

यह MVC 3 में थोड़ा अलग होने जा रहा है।

मान लें कि हमारे पास एक नियंत्रक है और गेट पद्धति के साथ एक दृश्य है

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 के Application_Start () में कमांड

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

यह एक अच्छा शुरुआती बिंदु है, लेकिन यह सही ढंग से लागू नहीं करता है IModelBinder, विशेष रूप से सत्यापन के बारे में। इसके अलावा, यह तभी काम करता है के नाम DateTimeहै dateTime
सैम

2
इसके अलावा, मैंने पाया है कि DateTime?केवल तभी काम करें जब आप किसी अन्य कॉल के ModelBinders.Binders.Addसाथ जोड़ें typeof(DateTime?)
सैम

8

यह भी ध्यान देने योग्य है कि अपने स्वयं के मॉडल बांधने के बिना भी कई अलग-अलग प्रारूप पार्स करने योग्य हो सकते हैं।

उदाहरण के लिए अमेरिका में निम्नलिखित सभी तार समतुल्य हैं और स्वचालित रूप से उसी डेटटाइम मान के लिए बाध्य हो जाते हैं :

/ कंपनी / प्रेस / मई% 2001% 202,008

/ कंपनी / प्रेस / 2008/05/01

/ कंपनी / प्रेस / 2008/05/01

मैं दृढ़ता से yyyy-mm-dd का उपयोग करने का सुझाव दूंगा क्योंकि यह बहुत अधिक पोर्टेबल है। आप वास्तव में कई स्थानीय स्वरूपों को संभालने से निपटना नहीं चाहते हैं। यदि कोई व्यक्ति 5 जनवरी की बजाय 1 मई को उड़ान भरता है, तो आपके पास बड़े मुद्दे हैं!

नायब: मैं स्पष्ट नहीं हूँ कि अगर yyyy-mm-dd को सभी संस्कृतियों में सार्वभौमिक रूप से पार्स किया जाता है, तो शायद जो कोई जानता है वह टिप्पणी जोड़ सकता है।


3
चूँकि कोई नहीं कहता है कि yyyy-MM-dd सार्वभौमिक नहीं है, मुझे लगता है कि यह है।
दीरचो

यह एक मॉडल बाइंडर का उपयोग करने से बेहतर है। .datepicker ("विकल्प", "dateFormat", "yy-mm-dd") या बस इसे डिफ़ॉल्ट में सेट करें।
बार्ट कैलिक्सो

6

ToISOString () का उपयोग करने का प्रयास करें। यह ISO8601 प्रारूप में स्ट्रिंग लौटाता है।

विधि प्राप्त करें

जावास्क्रिप्ट

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

सी#

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

पोस्ट विधि

जावास्क्रिप्ट

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

सी#

[HttpPost]
public JsonResult Do(DateTime date)
{
     return Json(date.ToString());
}

5

मैंने नीचे दिए गए कॉन्फिगरेशन को अपने MVC4 पर सेट किया है और यह एक आकर्षण की तरह काम करता है

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

3
यह मेरे लिए भी काम किया। ध्यान दें कि वैश्वीकरण तत्व कॉन्फ़िगरेशन> System.Web के अंतर्गत जाता है। msdn.microsoft.com/en-us/library/hy4kkhe0%28v=vs.85%29.aspx
जौन

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

            }
        }
    }
}

यह काम नहीं करता है। dd-MM-yyyy अभी भी मान्यता प्राप्त नहीं है
jao

1
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
आपको कुछ स्पष्टीकरण जोड़कर अपने उत्तर को अधिक समृद्ध बनाना चाहिए।
अलेक्जेंड्रे लावोई

स्मृति से, यह बिल्ट-इन मॉडल बाइंडर्स के काम करने के तरीके के अनुरूप नहीं है, इसलिए इसमें वैसा ही द्वितीयक व्यवहार नहीं हो सकता है जैसे सत्यापन के लिए टाइप किए गए मान को बनाए रखना।
सैम

1

मैंने सेट किया 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");
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.