79 Stimmen

Wie man eine Zeit in ein Date-Objekt aus Benutzereingaben in JavaScript parsen?

Ich arbeite an einem Formular-Widget, mit dem Benutzer eine Tageszeit in eine Texteingabe eingeben können (für eine Kalenderanwendung). Mit JavaScript (wir sind mit jQuery FWIW), möchte ich den besten Weg, um den Text zu parsen, die der Benutzer in ein JavaScript eingibt finden Date() Objekt, so dass ich leicht Vergleiche und andere Dinge damit durchführen kann.

Ich habe die parse() Methode und ist für meine Bedürfnisse ein wenig zu wählerisch. Ich würde erwarten, dass sie die folgenden Beispieleingabezeiten (zusätzlich zu anderen logisch ähnlichen Zeitformaten) erfolgreich als dieselben parsen kann Date() Objekt:

  • 13:00 Uhr
  • 13:00 Uhr.
  • 1:00 p
  • 13:00 Uhr
  • 13:00 Uhr.
  • 1:00p
  • 13 Uhr
  • 13.00 Uhr.
  • 1 p
  • 13 Uhr
  • 13.00 Uhr.
  • 1p
  • 13:00
  • 13

Ich denke, dass ich reguläre Ausdrücke verwenden könnte, um die Eingabe aufzuteilen und die Informationen zu extrahieren, die ich zum Erstellen meiner Date() Objekt. Wie lässt sich dies am besten bewerkstelligen?

78voto

John Resig Punkte 34001

Eine schnelle Lösung, die mit der von Ihnen angegebenen Eingabe funktioniert:

function parseTime( t ) {
   var d = new Date();
   var time = t.match( /(\d+)(?::(\d\d))?\s*(p?)/ );
   d.setHours( parseInt( time[1]) + (time[3] ? 12 : 0) );
   d.setMinutes( parseInt( time[2]) || 0 );
   return d;
}

var tests = [
  '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', '1a', '12', '12a', '12p', '12am', '12pm', '2400am', '2400pm', '2400', 
  '1000', '100', '123', '2459', '2359', '2359am', '1100', '123p',
  '1234', '1', '9', '99', '999', '9999', '99999', '0000', '0011', '-1', 'mioaw' ];

for ( var i = 0; i < tests.length; i++ ) {
  console.log( tests[i].padStart( 9, ' ' ) + " = " + parseTime(tests[i]) );
}

Es sollte auch für einige andere Sorten funktionieren (auch wenn man z.B. eine bestimmte Sorte verwendet, wird es funktionieren). Offensichtlich ist dies ziemlich grob, aber es ist auch ziemlich leicht (viel billiger zu verwenden, dass als eine vollständige Bibliothek, zum Beispiel).

Warnung: Der Code funktioniert nicht mit 12:00 AM, usw.

55voto

Nathan Villaescusa Punkte 16411

Alle angegebenen Beispiele funktionieren nicht für Zeiten zwischen 12:00 und 12:59 Uhr. Sie geben auch einen Fehler aus, wenn die Regex nicht mit einer Zeit übereinstimmt. Das Folgende behandelt dies:

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

var tests = [
  '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', '1a', '12', '12a', '12p', '12am', '12pm', '2400am', '2400pm', '2400', 
  '1000', '100', '123', '2459', '2359', '2359am', '1100', '123p',
  '1234', '1', '9', '99', '999', '9999', '99999', '0000', '0011', '-1', 'mioaw' ];

for ( var i = 0; i < tests.length; i++ ) {
  console.log( tests[i].padStart( 9, ' ' ) + " = " + parseTime(tests[i]) );
}

Dies funktioniert bei Zeichenketten, die irgendwo eine Zeitangabe enthalten. So würde "abcde12:00pmdef" geparst werden und 12 pm zurückgeben. Wenn das gewünschte Ergebnis ist, dass nur eine Zeit zurückgegeben wird, wenn die Zeichenfolge nur eine Zeit enthält, kann der folgende reguläre Ausdruck verwendet werden, vorausgesetzt, Sie ersetzen "time[4]" durch "time[6]".

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

32voto

Jim Punkte 70896

Machen Sie sich nicht die Mühe, es selbst zu tun, verwenden Sie einfach datejs .

16voto

claviska Punkte 12210

Die meisten der Regex-Lösungen hier werfen Fehler, wenn die Zeichenkette nicht geparst werden kann, und nicht viele von ihnen berücksichtigen Zeichenketten wie 1330 o 130pm . Obwohl diese Formate vom Auftraggeber nicht angegeben wurden, halte ich sie für entscheidend für die Analyse von Daten, die von Menschen eingegeben werden.

All dies brachte mich auf den Gedanken, dass die Verwendung eines regulären Ausdrucks vielleicht nicht der beste Ansatz für dieses Problem ist.

Meine Lösung ist eine Funktion, die nicht nur die Zeit analysiert, sondern auch ein Ausgabeformat und einen Schritt (Intervall) angibt, auf den die Minuten aufgerundet werden sollen. Mit etwa 70 Zeilen ist sie immer noch leichtgewichtig und analysiert alle oben genannten Formate sowie solche ohne Doppelpunkte.

  • Demo: http://jsfiddle.net/HwwzS/1/
  • Code : https://gist.github.com/claviska/4744736

    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');

    }

    var tests = [ '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', '1a', '12', '12a', '12p', '12am', '12pm', '2400am', '2400pm', '2400', '1000', '100', '123', '2459', '2359', '2359am', '1100', '123p', '1234', '1', '9', '99', '999', '9999', '99999', '0000', '0011', '-1', 'mioaw' ];

    for ( var i = 0; i < tests.length; i++ ) { console.log( tests[i].padStart( 9, ' ' ) + " = " + parseTime(tests[i]) ); }

12voto

Patrick McElhaney Punkte 55251

Hier ist eine Verbesserung gegenüber Joes Version . Sie können ihn gerne weiter bearbeiten.

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

var tests = [
  '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', '1a', '12', '12a', '12p', '12am', '12pm', '2400am', '2400pm', '2400', 
  '1000', '100', '123', '2459', '2359', '2359am', '1100', '123p',
  '1234', '1', '9', '99', '999', '9999', '99999', '0000', '0011', '-1', 'mioaw' ];

for ( var i = 0; i < tests.length; i++ ) {
  console.log( tests[i].padStart( 9, ' ' ) + " = " + parseTime(tests[i]) );
}

Änderungen:

  • Radix-Parameter zu den parseInt()-Aufrufen hinzugefügt (damit jslint sich nicht beschwert).
  • Die Regex wurde case-insenstive gemacht, so dass "2:23 PM" wie "2:23 pm" funktioniert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X