¿Cómo analizar una hora en un objeto Fecha a partir de la entrada del usuario en JavaScript?

Resuelto Joe Lencioni asked hace 15 años • 24 respuestas

Estoy trabajando en un widget de formulario para que los usuarios ingresen una hora del día en una entrada de texto (para una aplicación de calendario). Usando JavaScript (estamos usando jQuery FWIW), quiero encontrar la mejor manera de analizar el texto que el usuario ingresa en un Date()objeto JavaScript para poder realizar comparaciones y otras cosas fácilmente.

Probé el parse()método y es demasiado exigente para mis necesidades. Esperaría que pudiera analizar con éxito los siguientes ejemplos de horas de entrada (además de otros formatos de hora lógicamente similares) como el mismo Date()objeto:

  • 13:00
  • 13:00
  • 13:00
  • 13:00
  • 13:00.
  • 1:00p.m.
  • 13:00
  • 13:00
  • 1p
  • 13:00
  • 13:00 horas
  • 1p
  • 13:00
  • 13

Estoy pensando que podría usar expresiones regulares para dividir la entrada y extraer la información que quiero usar para crear mi Date()objeto. ¿Cuál es la mejor manera de hacer esto?

Joe Lencioni avatar Sep 27 '08 02:09 Joe Lencioni
Aceptado

Una solución rápida que funciona con la entrada que ha especificado:

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

También debería funcionar para algunas otras variedades (incluso si se usa am, seguirá funcionando, por ejemplo). Obviamente esto es bastante tosco pero también es bastante liviano (mucho más barato usarlo que una biblioteca completa, por ejemplo).

Advertencia: el código no funciona a las 12:00 a. m., etc.

John Resig avatar Sep 26 '2008 19:09 John Resig

Todos los ejemplos proporcionados no funcionan entre las 12:00 a. m. y las 0:59 a. m. También arrojan un error si la expresión regular no coincide con una hora. Lo siguiente maneja esto:

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

Esto funcionará para cadenas que contengan una hora en cualquier lugar de su interior. Por lo tanto, "abcde12:00pmdef" se analizaría y devolvería las 12 p. m. Si el resultado deseado es que solo devuelve una hora cuando la cadena solo contiene una hora, se puede usar la siguiente expresión regular siempre que reemplace "hora[4]" con "hora[6]".

/^(\d+)(:(\d\d))?\s*((a|(p))m?)?$/i
Nathan Villaescusa avatar Feb 02 '2010 23:02 Nathan Villaescusa

No te molestes en hacerlo tú mismo, solo usa datejs .

Jim avatar Sep 26 '2008 19:09 Jim

Aquí hay una mejora en la versión de Joe . No dudes en editarlo más.

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

Cambios:

  • Se agregó el parámetro radix a las llamadas parseInt() (para que jslint no se queje).
  • Se hizo que la expresión regular no distinga entre mayúsculas y minúsculas para que "2:23 p. m." funcione como "2:23 p. m."
Patrick McElhaney avatar Dec 03 '2008 19:12 Patrick McElhaney