What is the best way to parse a time into a Date o

2019-01-01 15:42发布

I am working on a form widget for users to enter a time of day into a text input (for a calendar application). Using JavaScript (we are using jQuery FWIW), I want to find the best way to parse the text that the user enters into a JavaScript Date() object so I can easily perform comparisons and other things on it.

I tried the parse() method and it is a little too picky for my needs. I would expect it to be able to successfully parse the following example input times (in addition to other logically similar time formats) as the same Date() object:

  • 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

I am thinking that I might use regular expressions to split up the input and extract the information I want to use to create my Date() object. What is the best way to do this?

20条回答
公子世无双
2楼-- · 2019-01-01 15:50

This is a more rugged approach that takes into account how users intend to use this type of input. For example, if a user entered "12", they would expect it to be 12pm (noon), and not 12am. The below function handles all of this. It is also available here: http://blog.de-zwart.net/2010-02/javascript-parse-time/

/**
 * Parse a string that looks like time and return a date object.
 * @return  Date object on success, false on error.
 */
String.prototype.parseTime = function() {
    // trim it and reverse it so that the minutes will always be greedy first:
    var value = this.trim().reverse();

    // We need to reverse the string to match the minutes in greedy first, then hours
    var timeParts = value.match(/(a|p)?\s*((\d{2})?:?)(\d{1,2})/i);

    // This didnt match something we know
    if (!timeParts) {
        return false;
    }

    // reverse it:
    timeParts = timeParts.reverse();

    // Reverse the internal parts:
    for( var i = 0; i < timeParts.length; i++ ) {
        timeParts[i] = timeParts[i] === undefined ? '' : timeParts[i].reverse();
    }

    // Parse out the sections:
    var minutes = parseInt(timeParts[1], 10) || 0;
    var hours = parseInt(timeParts[0], 10);
    var afternoon = timeParts[3].toLowerCase() == 'p' ? true : false;

    // If meridian not set, and hours is 12, then assume afternoon.
    afternoon = !timeParts[3] && hours == 12 ? true : afternoon;
    // Anytime the hours are greater than 12, they mean afternoon
    afternoon = hours > 12 ? true : afternoon;
    // Make hours be between 0 and 12:
    hours -= hours > 12 ? 12 : 0;
    // Add 12 if its PM but not noon
    hours += afternoon && hours != 12 ? 12 : 0;
    // Remove 12 for midnight:
    hours -= !afternoon && hours == 12 ? 12 : 0;

    // Check number sanity:
    if( minutes >= 60 || hours >= 24 ) {
        return false;
    }

    // Return a date object with these values set.
    var d = new Date();
    d.setHours(hours);
    d.setMinutes(minutes);
    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, ' ' ) + " = " + tests[i].parseTime() );
}

This is a string prototype, so you can use it like so:

var str = '12am';
var date = str.parseTime();
查看更多
初与友歌
3楼-- · 2019-01-01 15:51

I have made some modifications to the function above to support a few more formats.

  • 1400 -> 2:00 PM
  • 1.30 -> 1:30 PM
  • 1:30a -> 1:30 AM
  • 100 -> 1:00 AM

Ain't cleaned it up yet but works for everything I can think of.

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

    var time = timeString.match(/^(\d+)([:\.](\d\d))?\s*((a|(p))m?)?$/i);

    if (time == null) return null;

    var m = parseInt(time[3], 10) || 0;
    var hours = parseInt(time[1], 10);

    if (time[4]) time[4] = time[4].toLowerCase();

    // 12 hour time
    if (hours == 12 && !time[4]) {
        hours = 12;
    }
    else if (hours == 12 && (time[4] == "am" || time[4] == "a")) {
        hours += 12;
    }
    else if (hours < 12 && (time[4] != "am" && time[4] != "a")) {
        hours += 12;
    }
    // 24 hour time
    else if(hours > 24 && hours.toString().length >= 3) {
        if(hours.toString().length == 3) {
           m = parseInt(hours.toString().substring(1,3), 10);
           hours = parseInt(hours.toString().charAt(0), 10);
        }
        else if(hours.toString().length == 4) {
           m = parseInt(hours.toString().substring(2,4), 10);
           hours = parseInt(hours.toString().substring(0,2), 10);
        }
    }

    var d = new Date();
    d.setHours(hours);
    d.setMinutes(m);
    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]) );
}

查看更多
孤独总比滥情好
4楼-- · 2019-01-01 15:52

The time package is 0.9kbs in size. Available with NPM and bower package managers.

Here's an example straight from the README.md:

var t = Time('2p');
t.hours();             // 2
t.minutes();           // 0
t.period();            // 'pm'
t.toString();          // '2:00 pm'
t.nextDate();          // Sep 10 2:00 (assuming it is 1 o'clock Sep 10)
t.format('hh:mm AM')   // '02:00 PM'
t.isValid();           // true
Time.isValid('99:12'); // false
查看更多
牵手、夕阳
5楼-- · 2019-01-01 15:53

Why not use validation to narrow down what a user can put in and simplify the list to only include formats that can be parsed (or parsed after some tweaking).

I don't think it's asking too much to require a user to put a time in a supported format.

dd:dd A(m)/P(m)

dd A(m)/P(m)

dd

查看更多
怪性笑人.
6楼-- · 2019-01-01 15:53

An improvement to Patrick McElhaney's solution (his does not handle 12am correctly)

function parseTime( timeString ) {
var d = new Date();
var time = timeString.match(/(\d+)(:(\d\d))?\s*([pP]?)/i);
var h = parseInt(time[1], 10);
if (time[4])
{
    if (h < 12)
        h += 12;
}
else if (h == 12)
    h = 0;
d.setHours(h);
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', '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]) );
}

查看更多
刘海飞了
7楼-- · 2019-01-01 15:54

Lots of answers so one more won't hurt.

/**
 * Parse a time in nearly any format
 * @param {string} time - Anything like 1 p, 13, 1:05 p.m., etc.
 * @returns {Date} - Date object for the current date and time set to parsed time
*/
function parseTime(time) {
  var b = time.match(/\d+/g);
  
  // return undefined if no matches
  if (!b) return;
  
  var d = new Date();
  d.setHours(b[0]>12? b[0] : b[0]%12 + (/p/i.test(time)? 12 : 0), // hours
             /\d/.test(b[1])? b[1] : 0,     // minutes
             /\d/.test(b[2])? b[2] : 0);    // seconds
  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', '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]) );
}

To be properly robust, it should check that each value is within range of allowed values, e.g if am/pm hours must be 1 to 12 inclusive, otherwise 0 to 24 inclusive, etc.

查看更多
登录 后发表回答