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

时间:2020-03-06 14:48:05  来源:igfitidea点击:

我正在使用一个表单小部件,供用户在文本输入中输入一天中的某个时间(对于日历应用程序)。使用JavaScript(我们使用的是jQuery FWIW),我想找到解析用户输入到JavaScriptDate()对象中的文本的最佳方法,以便我可以轻松地对其进行比较和其他操作。

我尝试了parse()方法,它对于我的需求有点挑剔。我希望它能够成功地将以下示例输入时间(除了其他逻辑上相似的时间格式)解析为相同的Date()对象:

  • 1:00 PM
  • 1:00 PM。
  • 下午1:00
  • 1:00 PM
  • 1:00 PM。
  • 1:00p
  • 下午1点
  • 下午1点
  • 1个
  • 下午1点
  • 下午1点
  • 1p
  • 13:00
  • 13

我在想我可能会使用正则表达式来分割输入并提取要用于创建Date()对象的信息。做这个的最好方式是什么?

解决方案

不用自己动手,只需使用datejs。

为什么不使用验证来缩小用户可以输入的内容,并简化列表,使其仅包含可以解析(或者在某些调整后解析)的格式。

我认为要求用户以受支持的格式放置时间并不要求太多。

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

dd A(m)/ P(m)

dd

一种适用于我们指定的输入的快速解决方案:

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

它也应该适用于其他几个品种(即使使用了上午,例如仍然可以使用)。显然,这很粗糙,但也很轻巧(例如,使用它比完整的库便宜得多)。

Warning: The code doe not work with 12:00 AM, etc.

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

这是对Joe版本的改进。随时对其进行进一步编辑。

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

变化:

  • 在parseInt()调用中添加了基数参数(因此jslint不会抱怨)。
  • 使正则表达式具有区分大小写的功能,因此" 2:23 PM"的工作方式类似于" 2:23 pm"

/(\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 );

谢谢

提供的所有示例在从12:00 am到12:59 am的时间内都无法正常工作。如果正则表达式与时间不匹配,它们也会引发错误。以下是处理此问题的方法:

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

这是一种更坚固的方法,它考虑了用户打算如何使用这种类型的输入。例如,如果用户输入" 12",则他们希望它是下午12点(中午)而不是上午12点。下面的函数可以处理所有这一切。也可以在这里找到: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();

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

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

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

对于所有使用以下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]) );
}