代码之家  ›  专栏  ›  技术社区  ›  Joe Lencioni

从Javascript中的用户输入将时间解析为日期对象的最佳方法是什么?

  •  62
  • Joe Lencioni  · 技术社区  · 17 年前

    Date() 对象,以便我可以轻松地对其执行比较和其他操作。

    我试过了 parse() 方法,它对我的需要有点太挑剔了。我希望它能够成功地解析以下示例输入时间(以及其他逻辑上类似的时间格式),如下所示 日期(

    • 下午1:00
    • 下午1点
    • 下午1:00
    • 下午1点。
    • 下午1点
    • 下午1点
    • 1便士
    • 下午1点。
    • 1p
    • 13:00

    日期( 对象最好的方法是什么?

    20 回复  |  直到 5 年前
        1
  •  76
  •   Dave Jarvis James Eichele    8 年前

    对您指定的输入有效的快速解决方案:

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

    警告:该代码在12:00 AM等时间不起作用。

        2
  •  55
  •   Dave Jarvis James Eichele    8 年前

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

    这将适用于包含时间的字符串。因此,“abcde12:00pmdef”将被解析并返回12 pm。如果期望的结果是它只返回字符串中仅包含时间的时间,则可以使用以下正则表达式,前提是将“time[4]”替换为“time[6]”。

    /^(\d+)(:(\d\d))?\s*((a|(p))m?)?$/i
    
        3
  •  32
  •   Jim os x nerd    17 年前
        4
  •  16
  •   Dave Jarvis James Eichele    8 年前

    这里的大多数正则表达式解决方案在字符串无法解析时都会抛出错误,并且它们中的很多都不会考虑像这样的字符串 1330 130pm

    我的解决方案是一个函数,它不仅解析时间,还允许您指定输出格式和将分钟舍入到的步长(间隔)。大约有70行,它仍然是轻量级的,可以解析前面提到的所有格式以及没有冒号的格式。

    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]) );
    }
        5
  •  12
  •   Justin    8 年前

    Joe's version . 欢迎进一步编辑。

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

        6
  •  3
  •   Dave Jarvis James Eichele    8 年前

    在实现John Resig的解决方案时,我遇到了几个难题。以下是我根据他的答案使用的修改函数:

    function parseTime(timeString)
    {
      if (timeString == '') return null;
      var d = new Date();
      var time = timeString.match(/(\d+)(:(\d\d))?\s*(p?)/);
      d.setHours( parseInt(time[1]) + ( ( parseInt(time[1]) < 12 && time[4] ) ? 12 : 0) );
      d.setMinutes( parseInt(time[3]) || 0 );
      d.setSeconds(0, 0);
      return d;
    } // parseTime()
    
    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]) );
    }
        7
  •  3
  •   Dave Jarvis James Eichele    8 年前

    对于所有使用24小时时钟且支持以下功能的用户,这里有一个解决方案:

    • 0820->08:20
    • 32->03:02
    • 124->12:04

    function parseTime(text) {
      var time = text.match(/(\d?\d):?(\d?\d?)/);
    	var h = parseInt(time[1], 10);
    	var m = parseInt(time[2], 10) || 0;
    	
    	if (h > 24) {
            // try a different format
    		time = text.match(/(\d)(\d?\d?)/);
    		h = parseInt(time[1], 10);
    		m = parseInt(time[2], 10) || 0;
    	} 
    	
      var d = new Date();
      d.setHours(h);
      d.setMinutes(m);
      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]) );
    }
        8
  •  2
  •   Sgnl Ben Stafford    9 年前

    这个 time

    下面是一个直接来自 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
    
        9
  •  2
  •   Dave Jarvis James Eichele    8 年前

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

    这是一个字符串原型,因此您可以这样使用它:

    var str = '12am';
    var date = str.parseTime();
    
        10
  •  2
  •   V. Rubinetti    7 年前

    其他答案汇编表

    不敢相信

    试图用所有这些不同的算法测试所有的边缘案例让我头晕目眩,所以我冒昧地将这个线程中的所有答案和测试编译成一个方便的表格。

    代码(和结果表)太大,无法包含内联代码,因此我制作了一个JSFIDLE:

    http://jsfiddle.net/jLv16ydb/4/show

    // heres some filler code of the functions I included in the test,
    // because StackOverfleaux wont let me have a jsfiddle link without code
    Functions = [
        JohnResig,
        Qwertie,
        PatrickMcElhaney,
        Brad,
        NathanVillaescusa,
        DaveJarvis,
        AndrewCetinic,
        StefanHaberl,
        PieterDeZwart,
        JoeLencioni,
        Claviska,
        RobG,
        DateJS,
        MomentJS
    ];
    // I didn't include `date-fns`, because it seems to have even more
    // limited parsing than MomentJS or DateJS
    

    请随意拨弄我的小提琴,添加更多的算法和测试用例

    我没有在结果和“预期”输出之间添加任何比较,因为在某些情况下,“预期”输出可能会引起争论(例如,应该) 12 被解释为 12:00am 12:00pm ?). 你必须浏览表格,看看哪种算法对你最有意义。

    颜色不一定表示输出的质量或“预期”,它们只表示输出的类型:

    • red =抛出js错误

    • yellow undefined , null , NaN , "" "invalid date" )

    • green =js Date() 对象

    • light green =其他一切

    对象是输出,我将其转换为24小时 HH:mm 格式便于比较。

        11
  •  1
  •   Andrew M. Andrews III    16 年前

    AnyTime.Converter可以以多种不同格式解析日期/时间:

    http://www.ama3.com/anytime/

        12
  •  1
  •   Dave Jarvis James Eichele    8 年前

    有很多答案,所以再多一个就不会有问题了。

    /**
     * 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]) );
    }

        13
  •  1
  •   Dave Jarvis James Eichele    8 年前

    我对上面的函数做了一些修改,以支持更多的格式。

    • 1400->下午2:00

    我还没把它清理干净,但我能想到的一切都有用。

    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]) );
    }
        14
  •  1
  •   Dave Jarvis James Eichele    8 年前

    1. 确定经络是否正常 post meridiem
    2. 将输入数字转换为整数值。
    3. 0到24之间的时间:小时是点,没有分钟(12小时是下午)。
    4. 100和2359之间的时间:小时div 100为点,分钟mod 100为余数。
    5. 从2400点开始的时间:小时为午夜,剩余分钟。
    6. 当小时数超过12时,减去12并强制后梅里迪姆为真。
    7. 当分钟数超过59时,强制至59。

    将小时、分钟和post meridiem转换为日期对象对于读者来说是一项练习(许多其他答案都说明了如何实现这一点)。

    "use strict";
    
    String.prototype.toTime = function () {
      var time = this;
      var post_meridiem = false;
      var ante_meridiem = false;
      var hours = 0;
      var minutes = 0;
    
      if( time != null ) {
        post_meridiem = time.match( /p/i ) !== null;
        ante_meridiem = time.match( /a/i ) !== null;
    
        // Preserve 2400h time by changing leading zeros to 24.
        time = time.replace( /^00/, '24' );
    
        // Strip the string down to digits and convert to a number.
        time = parseInt( time.replace( /\D/g, '' ) );
      }
      else {
        time = 0;
      }
    
      if( time > 0 && time < 24 ) {
        // 1 through 23 become hours, no minutes.
        hours = time;
      }
      else if( time >= 100 && time <= 2359 ) {
        // 100 through 2359 become hours and two-digit minutes.
        hours = ~~(time / 100);
        minutes = time % 100;
      }
      else if( time >= 2400 ) {
        // After 2400, it's midnight again.
        minutes = (time % 100);
        post_meridiem = false;
      }
    
      if( hours == 12 && ante_meridiem === false ) {
        post_meridiem = true;
      }
    
      if( hours > 12 ) {
        post_meridiem = true;
        hours -= 12;
      }
    
      if( minutes > 59 ) {
        minutes = 59;
      }
    
      var result =
        (""+hours).padStart( 2, "0" ) + ":" + (""+minutes).padStart( 2, "0" ) +
        (post_meridiem ? "PM" : "AM");
    
      return result;
    };
    
    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].toTime() );
    }

    对于jQuery,新定义的字符串原型使用如下:

      <input type="text" class="time" />
    
      $(".time").change( function() {
        var $this = $(this);
        $(this).val( time.toTime() );
      });
    
        15
  •  1
  •   Qwertie    8 年前

    • 识别秒和毫秒
    • 退换商品 undefined 无效输入,如“13:00pm”或“11:65”
    • localDate 参数,否则返回Unix历元上的UTC时间(1970年1月1日)。
    • 支持军事时间 1330 (要禁用,请在正则表达式中设置第一个必需的“:”)
    • 允许24小时作为0小时的同义词,但不允许25小时。
    • 要求时间在字符串的开头(要禁用,请删除 ^\s* 在正则表达式中)
    • 具有实际检测输出不正确时的测试代码。

    编辑:它现在是一个 package timeToString 格式化程序: npm i simplertime


    /**
     * Parses a string into a Date. Supports several formats: "12", "1234",
     * "12:34", "12:34pm", "12:34 PM", "12:34:56 pm", and "12:34:56.789".
     * The time must be at the beginning of the string but can have leading spaces.
     * Anything is allowed after the time as long as the time itself appears to
     * be valid, e.g. "12:34*Z" is OK but "12345" is not.
     * @param {string} t Time string, e.g. "1435" or "2:35 PM" or "14:35:00.0"
     * @param {Date|undefined} localDate If this parameter is provided, setHours
     *        is called on it. Otherwise, setUTCHours is called on 1970/1/1.
     * @returns {Date|undefined} The parsed date, if parsing succeeded.
     */
    function parseTime(t, localDate) {
      // ?: means non-capturing group and ?! is zero-width negative lookahead
      var time = t.match(/^\s*(\d\d?)(?::?(\d\d))?(?::(\d\d))?(?!\d)(\.\d+)?\s*(pm?|am?)?/i);
      if (time) {
        var hour = parseInt(time[1]), pm = (time[5] || ' ')[0].toUpperCase();
        var min = time[2] ? parseInt(time[2]) : 0;
        var sec = time[3] ? parseInt(time[3]) : 0;
        var ms = (time[4] ? parseFloat(time[4]) * 1000 : 0);
        if (pm !== ' ' && (hour == 0 || hour > 12) || hour > 24 || min >= 60 || sec >= 60)
          return undefined;
        if (pm === 'A' && hour === 12) hour = 0;
        if (pm === 'P' && hour !== 12) hour += 12;
        if (hour === 24) hour = 0;
        var date = new Date(localDate!==undefined ? localDate.valueOf() : 0);
        var set = (localDate!==undefined ? date.setHours : date.setUTCHours);
        set.call(date, hour, min, sec, ms);
        return date;
      }
      return undefined;
    }
    
    var testSuite = {
      '1300':  ['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', '1:00:00PM', '1300', '13'],
      '1100':  ['11:00am', '11:00 AM', '11:00', '11:00:00', '1100'],
      '1359':  ['1:59 PM', '13:59', '13:59:00', '1359', '1359:00', '0159pm'],
      '100':   ['1:00am', '1:00 am', '0100', '1', '1a', '1 am'],
      '0':     ['00:00', '24:00', '12:00am', '12am', '12:00:00 AM', '0000', '1200 AM'],
      '30':    ['0:30', '00:30', '24:30', '00:30:00', '12:30:00 am', '0030', '1230am'],
      '1435':  ["2:35 PM", "14:35:00.0", "1435"],
      '715.5': ["7:15:30", "7:15:30am"],
      '109':   ['109'], // Three-digit numbers work (I wasn't sure if they would)
      '':      ['12:60', '11:59:99', '-12:00', 'foo', '0660', '12345', '25:00'],
    };
    
    var passed = 0;
    for (var key in testSuite) {
      let num = parseFloat(key), h = num / 100 | 0;
      let m = num % 100 | 0, s = (num % 1) * 60;
      let expected = Date.UTC(1970, 0, 1, h, m, s); // Month is zero-based
      let strings = testSuite[key];
      for (let i = 0; i < strings.length; i++) {
        var result = parseTime(strings[i]);
        if (result === undefined ? key !== '' : key === '' || expected !== result.valueOf()) {
          console.log(`Test failed at ${key}:"${strings[i]}" with result ${result ? result.toUTCString() : 'undefined'}`);
        } else {
          passed++;
        }
      }
    }
    console.log(passed + ' tests passed.');
    
        16
  •  0
  •   Wayne    17 年前

    我认为要求用户以支持的格式输入时间并不过分。

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

    dd A(m)/P(m)

        17
  •  0
  •   BNL user1738206    14 年前
    /(\d+)(?::(\d\d))(?::(\d\d))?\s*([pP]?)/ 
    
    // added test for p or P
    // added seconds
    
    d.setHours( parseInt(time[1]) + (time[4] ? 12 : 0) ); // care with new indexes
    d.setMinutes( parseInt(time[2]) || 0 );
    d.setSeconds( parseInt(time[3]) || 0 );
    

        18
  •  0
  •   Dave Jarvis James Eichele    8 年前

    Patrick McElhaney解决方案的改进(他的解决方案不能正确处理上午12点)

    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]) );
    }
        19
  •  0
  •   Souradeep Nanda    8 年前

    const toSeconds = s => s.split(':').map(v => parseInt(v)).reverse().reduce((acc,e,i) => acc + e * Math.pow(60,i))
    
        20
  •  0
  •   Dave Jarvis James Eichele    6 年前

    经过全面测试和调查 my other compilation answer ,我认为@Dave Jarvis的解决方案最接近我认为合理的输出和边缘案例处理。作为参考,我查看了Google Calendar的时间输入在退出文本框后重新格式化的时间。

    my compilation answer .

    // attempt to parse string as time. return js date object
    function parseTime(string) {
      string = String(string);
    
      var am = null;
    
      // check if "apm" or "pm" explicitly specified, otherwise null
      if (string.toLowerCase().includes("p")) am = false;
      else if (string.toLowerCase().includes("a")) am = true;
    
      string = string.replace(/\D/g, ""); // remove non-digit characters
      string = string.substring(0, 4); // take only first 4 digits
      if (string.length === 3) string = "0" + string; // consider eg "030" as "0030"
      string = string.replace(/^00/, "24"); // add 24 hours to preserve eg "0012" as "00:12" instead of "12:00", since will be converted to integer
    
      var time = parseInt(string); // convert to integer
      // default time if all else fails
      var hours = 12,
        minutes = 0;
    
      // if able to parse as int
      if (Number.isInteger(time)) {
        // treat eg "4" as "4:00pm" (or "4:00am" if "am" explicitly specified)
        if (time >= 0 && time <= 12) {
          hours = time;
          minutes = 0;
          // if "am" or "pm" not specified, establish from number
          if (am === null) {
            if (hours >= 1 && hours <= 12) am = false;
            else am = true;
          }
        }
        // treat eg "20" as "8:00pm"
        else if (time >= 13 && time <= 99) {
          hours = time % 24;
          minutes = 0;
          // if "am" or "pm" not specified, force "am"
          if (am === null) am = true;
        }
        // treat eg "52:95" as 52 hours 95 minutes 
        else if (time >= 100) {
          hours = Math.floor(time / 100); // take first two digits as hour
          minutes = time % 100; // take last two digits as minute
          // if "am" or "pm" not specified, establish from number
          if (am === null) {
            if (hours >= 1 && hours <= 12) am = false;
            else am = true;
          }
        }
    
        // add 12 hours if "pm"
        if (am === false && hours !== 12) hours += 12;
        // sub 12 hours if "12:00am" (midnight), making "00:00"
        if (am === true && hours === 12) hours = 0;
    
        // keep hours within 24 and minutes within 60
        // eg 52 hours 95 minutes becomes 4 hours 35 minutes
        hours = hours % 24;
        minutes = minutes % 60;
      }
    
      // convert to js date object
      var date = new Date();
      date.setHours(hours);
      date.setMinutes(minutes);
      date.setSeconds(0);
      return date;
    }
    
    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]) );
    }

    注: 这是以美国为中心的,因为对于某些模式,它默认为am/pm:

    • 1 => 13:00 1:00pm )
    • 1100 => 23:00 11:00pm )
    • 456 => 16:56 ( 4:56pm )
        21
  •  0
  •   Dharman vijay    5 年前

    我需要一个时间解析器函数,根据一些答案,我最终得到了这个函数

     function parse(time){
      let post_meridiem = time.match(/p/i) !== null;
      let result;
      time = time.replace(/[^\d:-]/g, '');
      let hours = 0;
      let minutes = 0;
      if (!time) return;
      let parts = time.split(':');
      if (parts.length > 2) time = parts[0] + ':' + parts[1];
      if (parts[0] > 59 && parts.length === 2) time = parts[0];
      if (!parts[0] && parts[1] < 60) minutes = parts[1];
      else if (!parts[0] && parts[1] >= 60) return;
      time = time.replace(/^00/, '24');
      time = parseInt(time.replace(/\D/g, ''));
      if (time >= 2500) return;
      if (time > 0 && time < 24 && parts.length === 1) hours = time;
      else if (time < 59) minutes = time;
      else if (time >= 60 && time <= 99 && parts[0]) {
        hours = ('' + time)[0];
        minutes = ('' + time)[1];
      } else if (time >= 100 && time <= 2359) {
        hours = ~~(time / 100);
        minutes = time % 100;
      } else if (time >= 2400) {
        hours = ~~(time / 100) - 24;
        minutes = time % 100;
        post_meridiem = false;
      }
      if (hours > 59 || minutes > 59) return;
      if (post_meridiem && hours !== 0) hours += 12;
      if (minutes > 59) minutes = 59;
      if (hours > 23) hours = 0;
      result = ('' + hours).padStart(2, '0') + ':' + ('' + minutes).padStart(2, '0');
      return result;
    }
     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', '0000', '0011', '-1', 'mioaw',
      "0820",
      "32",
      "124",
      "1330",
      "130pm",
      "456",
      ":40",
      ":90",
      "12:69",
      "50:90",
      "aaa12:34aaa",
      "aaa50:00aaa",
     ];
    
        for ( var i = 0; i < tests.length; i++ ) {
          console.log( tests[i].padStart( 9, ' ' ) + " = " + parse(tests[i]) );
        }
    在其他答案的汇编表上,这里有一个叉子 Compilation table of other answers