Validate Datetime on client

5

I have a model with a property of type DateTime :

[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
[DataType(DataType.Date, ErrorMessage="Data em formato inválido")]
public DateTime? Date {get;set;}

And in View :

@Html.TextBoxFor(model => model.Date)
@Html.ValidationMessageFor(model => model.Date)

When typing a date with the following value: 11/11/1111, it is the value not the format, and I send the POST, it passes in ModelState , but in SaveChange it causes error:

  

The conversion of a datetime2 data type to a datetime data type   resulted in an out-of-range value. The statement has been terminated.

What I have done so far and I did not succeed:

1 - In my Web.config the following attribute:

 <globalization uiCulture="pt-BR" culture="pt-BR" enableClientBasedCulture="true" requestEncoding="UTF-8" responseEncoding="UTF-8" fileEncoding="UTF-8" />

2 - Installation of jQuery globalize and jQuery Validate globalize . The load order is this:

<script src="~/Scripts/libs/jquery.globalize/globalize.js"></script>
<script src="~/Scripts/libs/jquery.globalize/cultures/globalize.culture.pt-BR.js"></script>

<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Content/Scripts/libs/jquery.validate/jquery.validate.globalize.min.js"></script>

3 - Handling number and dates using jQuery Validate + globalize , with the following code:

jQuery.extend(jQuery.validator.methods, {
    date: function (value, element) {
        return this.optional(element) || /^\d\d?\/\d\d?\/\d\d\d?\d?$/.test(value);
    },
    number: function (value, element) {
        return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);
    }
});

How to validate this date entry or create a "range" in the client rather than the server?

    
asked by anonymous 31.12.2014 / 02:56

3 answers

2

@Rod, your problem here is not validation of Type DateTime , but the Range allowed by type DateTime in SqlServer .

To solve this problem, you can change the column type in SqlServer to datetime2(7) , which is also the recommended type for new tables.

Or you can put a DataAnnotations to validate the Range, so that it looks similar to SqlServer

[DataType(DataType.DateTime, ErrorMessage="Isto não é um data")]
[Range(typeof(DateTime), "01/01/1753", "31/12/9999")]
public DateTime Date { get; set; }
    
18.02.2015 / 01:46
1

The problem in .NET

The translation of:

  

The conversion of a datetime2 data type to a datetime result in an out-of-range value.

It would be something like:

  

Converting the date type "datetime2" to "datetime" resulted in a value out of range / scope.

The range must be equal to or greater than "January 1, 1753" as per the msdn Date and Time Data .

  

These data types only support dates that occur after the introduction of the Gregorian calendar in England in 1753.

     

EN: These data support only dates that occur after the introduction of the Gregorian calendar in England in 1753.

Validation on the front end:

I'll assume that in 11/11/1111 is dia/mes/ano , the default used in Brazil, the code should look something like:

date: function (value, element) {
    var data, dataObjeto, ano;

    if (this.optional(element) || /^\d{2}\/\d{2}\/\d{4}$/.test(value)) {
        data       = value.split("/");
        dataObjeto = new Date(data[2], data[1] - 1, data[0]);
        ano        = dataObjeto.getFullYear();

        return (
            ano == data[2] &&
            dataObjeto.getMonth() === parseInt(data[1]) &&
            dataObjeto.getDate() === parseInt(data[0]) &&
            ano > 1900 && ano < 2100
        );
    }
    return false;
}

I'll explain the code:

  • data = value.split("/"); splits the date that is a string
  • dataObjeto = new Date(data[2], data[1] - 1, data[0]); , data[2] is the year, data[1] the month and data[0] the day, so the new Date constructor will be able to compare if the date is "valid".
  • ano == data[2] checks if the year of value is equal to the year that new Date "understood", if it is different it is because the date has been reset and the user probably put a wrong or random value.
  • dataObjeto.getMonth() === parseInt(data[1]) compares if the month was the same as received by value .
  • dataObjeto.getDate() === parseInt(data[0]) compares if day was the same as value .
  • ano > 1900 and ano < 2100 is your allowed range / range, you can change.

In this code if the user adds a date as is 29/02/2015 (it is not leap year, therefore there is no day 29) new Date will generate this date 2015-03-01T03:00:00.000Z (March 1, 2015), so the date entered by the user is invalid and the validator stays in false

Does the field display time and date:

[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy hh:mm}")]

You can use RegEx validation like this:

/^\d{2}\/\d{2}\/\d{4} \d{2}[:]\d{2}$/

And the code should look like this:

date: function (value, element) {
    "use strict";
    var horaData, data, hora, dataObjeto, ano;

    if (this.optional(element) || /^\d{2}\/\d{2}\/\d{4} \d{2}[:]\d{2}$/.test(value)) {
        horaData = value.split(" ");

        data = horaData[0].split("/");
        hora = horaData[1].split(":");

        dataObjeto = new Date(data[2], data[1] - 1, data[0], hora[0], hora[1]);
        ano = dataObjeto.getFullYear();

        return (
            ano === parseInt(data[2]) &&
            dataObjeto.getMinutes() === parseInt(hora[1]) &&
            dataObjeto.getHours() === parseInt(hora[0]) &&
            dataObjeto.getMonth() === parseInt(data[1]) - 1 &&
            dataObjeto.getDate() === parseInt(data[0]) &&
            ano > 1900 && ano < 2100
        );
    }
    return false;
},
    
15.01.2015 / 22:36
0

The resolution roadmap is in two answers that I have already written:

31.12.2014 / 03:11