什么是从Javascript中的用户inputparsingdate对象的最佳方式?

我正在为用户input文本input(日历应用程序)的一天中的时间的窗体小部件。 使用JavaScript(我们使用的是jQuery FWIW),我想findparsing用户input到JavaScript Date()对象中的文本的最佳方式,以便我可以轻松地对其进行比较和其他操作。

我尝试了parse()方法,这对我的需求来说太挑剔了。 我期望它能够成功parsing下面的示例input时间(除了其他逻辑上相似的时间格式)与相同的Date()对象:

  • 1:00 PM
  • 1:00 PM
  • 1:00 p
  • 1:00 PM
  • 1:00 PM。
  • 1:00P
  • 下午1点
  • 下午1点
  • 1页
  • 下午1点
  • 下午1点
  • 1P
  • 13:00
  • 13

我想我可能会使用正则expression式来分割input,并提取我想用来创build我的Date()对象的信息。 做这个的最好方式是什么?

一个快速的解决scheme,在你指定的input上工作:

 var times = ['1:00 pm','1:00 pm','1:00 p','1:00pm', '1:00p.m.','1:00p','1 pm','1 pm','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 ); } 

提供的所有例子都不能在上午十二点到十二点五十九分的时间内工作。 如果正则expression式与时间不匹配,它们也会抛出一个错误。 以下处理:

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

这将适用于其中包含时间任何地方的string。 所以“abcde12:00pmdef”将被parsing并返回12点。 如果期望的结果是只返回string中只包含时间的时间,则可以使用以下正则expression式,只要将“time [4]”replace为“time [6]”。

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

不要打扰你自己做,只要使用datejs 。

这里的大多数正则expression式解决scheme在string不能被parsing的时候会抛出错误,并且其中很多并不像1330或者130pm那样占据string。 即使这些格式没有被OP指定,但我发现它们对于人类input的parsingdate是至关重要的。

所有这些让我想到,使用正则expression式可能不是最好的方法。

我的解决scheme是一个函数,不仅parsing时间,而且还允许您指定一个输出格式和一个步骤(时间间隔)来分钟。 在大约70行,它仍然是轻量级的,parsing所有上述格式以及没有冒号的格式。

演示: http : //jsfiddle.net/HwwzS/1/

代码: 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'); } 

这是对Joe版本的改进。 随意编辑它进一步。

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

变化:

  • parseInt()调用添加了基数参数(所以jslint不会抱怨)。
  • 使正则expression式不区分大小写,所以“2:23 PM”就像“2:23 pm”

在实施John Resig的解决scheme时,我碰到了一些问题。 这里是我根据他的回答使用的修改函数:

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

下面是所有使用24小时钟的人的更多解决scheme:

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

注意,这个函数也支持stringparsing

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

这是一个更坚固的方法,考虑到用户打算如何使用这种types的input。 例如,如果用户input“12”,则他们预计是12点(中午),而不是12点。 下面的函数处理所有这一切。 它也可以在这里find: 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; } 

这是一个string原型,所以你可以像这样使用它:

 var str = '12am'; var date = str.parseTime(); 

AnyTime.Converter可以parsing许多不同格式的date/时间:

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

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

1400 – > 2:00 PM

1.30 – > 1:30 PM

1:30a – > 1:30 AM

100 – > 1:00 AM

还没有清理它,但为我所能想到的一切工作。

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

时间包是0.9kbs的大小。 NPM和凉亭包pipe理器可用。

这里是直接来自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 

为什么不使用validation来缩小用户可以放入的内容,并将列表简化为只包含可以parsing的格式(或者在调整后进行parsing)。

我不认为要求用户花费时间才能获得支持。

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

dd A(m)/ P(m)

DD

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

谢谢

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

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

很多的答案,所以多一点不会伤害。

 /** * Parse a time in nearly any format * @param {string} time - Anything like 1 p, 13, 1:05 pm, 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; } 

为了保持健壮性,应该检查每个值是否在允许值的范围内,例如,如果am / pm小时数必须是1到12(含),否则是0到24(含)等等。