74 votes

Quel est le meilleur moyen d’analyser une heure dans un objet Date à partir de la saisie utilisateur en Javascript?

Je suis en train de travailler sur une forme de widget pour les utilisateurs à entrer un moment de la journée dans une saisie de texte (pour une application de calendrier). À l'aide de JavaScript (nous sommes à l'aide de jQuery FWIW), je veux trouver la meilleure façon d'analyser le texte que l'utilisateur entre dans un JavaScript Date() objet donc je peut facilement effectuer des comparaisons et d'autres choses sur elle.

J'ai essayé de l' parse() méthode et c'est un peu trop pointilleux pour mes besoins. Je m'attends à ce qu'il soit capable d'analyser correctement l'exemple suivant la saisie d'heures (en plus des autres une logique similaire formats d'heure) que le même Date() objet:

  • 1:00 pm
  • 1:00
  • 1:00 p
  • 1:00pm
  • 1:00p.m.
  • 1:00p
  • 1 h
  • 1 h
  • 1 p
  • 1pm
  • 1p.m.
  • 1p
  • 13:00
  • 13

Je pense que je peux utiliser des expressions régulières pour séparer l'entrée et d'extraire les informations que je souhaite utiliser pour créer mon Date() objet. Quelle est la meilleure façon de le faire?

76voto

John Resig Points 24061

Une solution rapide qui fonctionne sur l'entrée que vous avez spécifiée:

 var times = ['1:00 pm','1:00 p.m.','1:00 p','1:00pm',
  '1:00p.m.','1:00p','1 pm','1 p.m.','1 p','1pm','1p.m.', '1p','13:00','13'];

for ( var i = 0; i < times.length; i++ ) {
  var d = new Date();
  var time = times[i].match(/(\d+)(?::(\d\d))?\s*(p?)/);
  d.setHours( parseInt(time[1]) + (time[3] ? 12 : 0) );
  d.setMinutes( parseInt(time[2]) || 0 );
  console.log( d );
}
 

Cela devrait également fonctionner pour quelques autres variétés (même si am est utilisé, il fonctionnera toujours - par exemple). Évidemment, c’est plutôt brut, mais c’est aussi assez léger (beaucoup moins cher à utiliser qu’une bibliothèque complète, par exemple).

55voto

Nathan Villaescusa Points 6750

Tous les exemples fournis ne fonctionnent fois à partir de 12:00 à 12:59 am. Ils ont également lever une erreur si la regex ne correspond pas à un temps. La suite de poignées ceci:

function parseTime(timeString) {    
    if (timeString == '') return null;

    var time = timeString.match(/(\d+)(:(\d\d))?\s*(p?)/i); 
    if (time == null) return null;

    var hours = parseInt(time[1],10);    
    if (hours == 12 && !time[4]) {
          hours = 0;
    }
    else {
        hours += (hours < 12 && time[4])? 12 : 0;
    }   
    var d = new Date();             
    d.setHours(hours);
    d.setMinutes(parseInt(time[3],10) || 0);
    d.setSeconds(0, 0);  
    return d;
}

Cela fonctionne pour des chaînes qui contiennent une fois n'importe où à l'intérieur d'eux. Donc "abcde12:00pmdef" serait analysé et retour à 12h. Si le résultat souhaité est qu'il retourne uniquement un moment où la chaîne ne contient qu'un temps l'expression régulière suivante peut être utilisée à condition de remplacer "le temps[4]" par "[6]".

/^(\d+)(:(\d\d))?\s*((a|(p))m?)?$/i

32voto

Jim Points 39574

Ne prenez pas la peine de le faire vous-même, utilisez simplement datejs .

16voto

claviska Points 2544

La plupart des regex solutions ici de générer des erreurs lors de la chaîne ne peut pas être analysé, et pas beaucoup d'entre eux représentent des chaînes de caractères comme 1330 ou 130pm. Même si ces formats n'étaient pas spécifiés par l'OP, je trouve critiques pour l'analyse des dates d'entrée par l'homme.

Tout cela m'a fait penser que l'utilisation d'une expression régulière peut ne pas être la meilleure approche pour ce.

Ma solution est une fonction qui non seulement traite le moment, mais vous permet également de spécifier le format de sortie et une étape (intervalle) à qui à tour de minutes. À environ 70 lignes, c'est toujours léger et analyse tout ce qui précède, ainsi que les formats sans les deux-points.

Démo: http://jsfiddle.net/HwwzS/1/

Code: https://gist.github.com/claviska/4744736

Et ci-dessous dans le cas où les liens de briser un jour:

function parseTime(time, format, step) {

    var hour, minute, stepMinute,
        defaultFormat = 'g:ia',
        pm = time.match(/p/i) !== null,
        num = time.replace(/[^0-9]/g, '');

    // Parse for hour and minute
    switch(num.length) {
        case 4:
            hour = parseInt(num[0] + num[1], 10);
            minute = parseInt(num[2] + num[3], 10);
            break;
        case 3:
            hour = parseInt(num[0], 10);
            minute = parseInt(num[1] + num[2], 10);
            break;
        case 2:
        case 1:
            hour = parseInt(num[0] + (num[1] || ''), 10);
            minute = 0;
            break;
        default:
            return '';
    }

    // Make sure hour is in 24 hour format
    if( pm === true && hour > 0 && hour < 12 ) hour += 12;

    // Force pm for hours between 13:00 and 23:00
    if( hour >= 13 && hour <= 23 ) pm = true;

    // Handle step
    if( step ) {
        // Step to the nearest hour requires 60, not 0
        if( step === 0 ) step = 60;
        // Round to nearest step
        stepMinute = (Math.round(minute / step) * step) % 60;
        // Do we need to round the hour up?
        if( stepMinute === 0 && minute >= 30 ) {
            hour++;
            // Do we need to switch am/pm?
            if( hour === 12 || hour === 24 ) pm = !pm;
        }
        minute = stepMinute;
    }

    // Keep within range
    if( hour <= 0 || hour >= 24 ) hour = 0;
    if( minute < 0 || minute > 59 ) minute = 0;

    // Format output
    return (format || defaultFormat)
        // 12 hour without leading 0
        .replace(/g/g, hour === 0 ? '12' : 'g')
        .replace(/g/g, hour > 12 ? hour - 12 : hour)
        // 24 hour without leading 0
        .replace(/G/g, hour)
        // 12 hour with leading 0
        .replace(/h/g, hour.toString().length > 1 ? (hour > 12 ? hour - 12 : hour) : '0' + (hour > 12 ? hour - 12 : hour))
        // 24 hour with leading 0
        .replace(/H/g, hour.toString().length > 1 ? hour : '0' + hour)
        // minutes with leading zero
        .replace(/i/g, minute.toString().length > 1 ? minute : '0' + minute)
        // simulate seconds
        .replace(/s/g, '00')
        // lowercase am/pm
        .replace(/a/g, pm ? 'pm' : 'am')
        // lowercase am/pm
        .replace(/A/g, pm ? 'PM' : 'AM');

}

12voto

Patrick McElhaney Points 22093

Voici une amélioration de la version de Joe . N'hésitez pas à le modifier davantage.

 parseTime(timeString)
{
  if (timeString == '') return null;
  var d = new Date();
  var time = timeString.match(/(\d+)(:(\d\d))?\s*(p?)/i);
  d.setHours( parseInt(time[1],10) + ( ( parseInt(time[1],10) < 12 && time[4] ) ? 12 : 0) );
  d.setMinutes( parseInt(time[3],10) || 0 );
  d.setSeconds(0, 0);
  return d;
}
 

Changements:

  • Ajout du paramètre radix aux appels parseInt () (pour que jslint ne se plaint pas).
  • Si la regex est insensible à la casse, "2:23 PM" fonctionne comme "2:23 pm"

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