37 votes

Safari JS ne peut pas analyser le format de date YYYY-MM-DD ?

Dans le cadre d'un projet sur lequel je travaille, j'ai besoin de valider une date entrée dans un fichier <input type="date">

Avec Safari 4/5 (sur Mac OSX), le Javascript ne parvient pas à analyser les dates du format suivant YYYY-MM-DD en retournant NaN au lieu de l'horodatage d'époque attendu.

J'utilise la technique suivante pour valider le champ juste avant que le formulaire ne soit soumis :

//value = '2010-06-21'
var stamp = Date.parse(value);
if (isNaN(stamp)) {
    //notify user
} else {
    value = new Date(stamp).format_mysql();
}

format_mysql() est une fonction prototype qui formate la date (correctement) au format MySQL Date-Time (YYYY-MM-DD).

Remplacer le - avec / (AAAA/MM/JJ) donne un horodatage "correct".

Je tiens à préciser que le champ doit accepter n'importe quel format de date, pas seulement AAAA-MM-JJ, et que, même si je le souhaite, je ne peux pas utiliser des bibliothèques comme Date.js.

Comment puis-je corriger cela, ou existe-t-il une meilleure façon d'analyser/valider une date ?

57voto

CMS Points 315406

Le comportement de la Date.parse dépend de l'implémentation. Sous ECMAScript 5, cette méthode peut analyser les dates au format ISO8601, mais je vous recommande d'effectuer l'analyse manuellement.

Il y a quelque temps, j'ai créé une fonction simple, qui peut gérer un argument de spécification de format :

function parseDate(input, format) {
  format = format || 'yyyy-mm-dd'; // default format
  var parts = input.match(/(\d+)/g), 
      i = 0, fmt = {};
  // extract date-part indexes from the format
  format.replace(/(yyyy|dd|mm)/g, function(part) { fmt[part] = i++; });

  return new Date(parts[fmt['yyyy']], parts[fmt['mm']]-1, parts[fmt['dd']]);
}

parseDate('06.21.2010', 'mm.dd.yyyy');
parseDate('21.06.2010', 'dd.mm.yyyy');
parseDate('2010/06/21', 'yyyy/mm/dd');
parseDate('2010-06-21');

Vous pouvez également détecter le comportement de l'ECMAScript 5 pour analyser les dates formatées ISO, en vérifiant si la balise Date.prototype.toISOString est disponible, par exemple :

if (typeof Date.prototype.toISOString == "function") {
  // ES5 ISO date parsing available
}

13voto

Vishnu Vardhana Points 71

En général, le format DD-MM-YYYY n'est pas pris en charge par Safari.

valeur = 2010/06/21 ; //doit fonctionner.

(ou)

valeur = nouvelle Date('2010-06-21'.replace(/-/g, "/")) ;

3voto

tc. Points 23958

le champ doit accepter tout format de date

Vous ne voulez pas dire ce que vous pensez.

  • Il est difficile de faire une distinction fiable entre M/D/Y (États-Unis) et D/M/Y (Royaume-Uni). Le D.M.Y. est plus courant au Royaume-Uni, mais il n'est en aucun cas universel.
  • Bonne chance pour les dates antérieures à 1600 environ - le calendrier grégorien (solaire) a été introduit en 1582 et n'a été adopté (presque universellement) qu'au 20e siècle (Wikipedia donne 1929). Le 30 février était une date valable en Suède.
  • OS X vous offre un choix de 13 ( !) calendriers, bien que le calendrier par défaut soit le calendrier grégorien.

Je vous recommande plutôt d'utiliser un widget de calendrier. Je pense que JQuery en a un, mais ICBW.

1voto

kennebec Points 33886

Vous pouvez obtenir une date non ambiguë à partir de l'entrée, mais vous devez tout de même la vérifier, afin qu'un utilisateur ne vous donne pas le 31 avril.

<fieldset id= "localdate"> 
<select id= "monthselect" size= "1"> 
<option selected= "selected"> January</option> 
<option> February</option> 
<option> March</option> 
<option> April</option> 
<option> May</option> 
<option> June</option> 
<option> July</option> 
<option> August</option> 
<option> September</option> 
<option> October</option> 
<option> November</option> 
<option> December</option> 
</select> 
<label> Date: <input name= "inputdate" size= "2" value= "1"> </label> 
<label> Year: <input name= "inputyear" size= "4" value= "2010"> </label> 
</fieldset> 

raccourci pour document.getElementsByName

function byName(s, n){ n= n || 0 ; return document.getElementsByName(s)[n] ; }

function getDateInput(){
    var day, y= parseInt(byName('inputyear').value),
    m= byName('monthselect').selectedIndex,
    d= parseInt(byName('inputdate').value);

    if(!y || y<1000 || y> 3000) throw 'Bad Year '+y;
    if((!d || d<1 || d> 32) throw 'Bad Date '+d;
    day= new Date(y,m,d);
    if(day.getDate()!= d) throw 'Bad Date '+d;
    value= day.format_mysql();
}

vous pouvez prédéfinir les champs pour qu'ils reflètent la date actuelle au chargement

onload= function(){
    var now= new Date();
    byName('inputyear').value= now.getFullYear();
    byName('monthselect').selectedIndex= now.getMonth();
    byName('inputdate').value= now.getDate();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X