Je travaille sur un widget de formulaire pour que les utilisateurs entrent une heure dans une entrée de texte (pour une application de calendrier). En utilisant JavaScript (nous utilisons jQuery FWIW), je souhaite trouver le meilleur moyen d’analyser le texte saisi par l’utilisateur dans un objet JavaScript Date()
afin de pouvoir effectuer facilement des comparaisons et autres opérations.
J'ai essayé la méthode parse()
et elle est un peu trop difficile pour mes besoins. Je m'attendrais à ce qu'il puisse analyser avec succès les exemples de temps de saisie suivants (en plus d'autres formats de temps similaires de manière logique) en tant que même objet Date()
:
Je pense que je pourrais utiliser des expressions régulières pour fractionner les entrées et extraire les informations que je souhaite utiliser pour créer mon objet Date()
. Quelle est la meilleure façon de procéder?
Une solution rapide qui fonctionne sur l'entrée que vous avez spécifiée:
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]) );
}
Cela devrait également fonctionner pour quelques autres variétés (même si on utilise un, cela fonctionnera toujours - par exemple). Évidemment, c’est plutôt brut, mais c’est aussi assez léger (beaucoup moins cher à utiliser qu’une bibliothèque complète, par exemple).
Attention: Le code ne fonctionne pas à 00h00, etc.
Tous les exemples fournis ne fonctionnent pas entre midi et 12h59. Ils génèrent également une erreur si l'expression régulière ne correspond pas à une heure. Ce qui suit gère ceci:
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]) );
}
Cela fonctionnera pour les chaînes qui contiennent une heure n'importe où à l'intérieur. Donc "abcde12: 00pmdef" serait analysé et renvoyé à midi. Si le résultat souhaité est qu'il ne renvoie qu'une heure lorsque la chaîne ne contient qu'une heure, l'expression régulière suivante peut être utilisée à condition de remplacer "time [4]" par "time [6]".
/^(\d+)(:(\d\d))?\s*((a|(p))m?)?$/i
Ne vous embêtez pas, utilisez simplement datejs .
La plupart des solutions d'expression rationnelle ici génèrent des erreurs lorsque la chaîne ne peut pas être analysée, et peu d'entre elles rendent compte de chaînes telles que 1330
ou 130pm
. Bien que ces formats n'aient pas été spécifiés par l'OP, je les trouve essentiels pour analyser les dates saisies par les humains.
Tout cela m'a amené à penser que l'utilisation d'une expression régulière n'était peut-être pas la meilleure approche pour cela.
Ma solution est une fonction qui non seulement analyse l'heure, mais vous permet également de spécifier un format de sortie et une étape (intervalle) auxquels arrondir les minutes. À environ 70 lignes, il est toujours léger et analyse tous les formats susmentionnés ainsi que ceux sans deux-points.
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]) );
}
Voici une amélioration de la version de Joe . N'hésitez pas à le modifier davantage.
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]) );
}
Changements:
J'ai rencontré quelques problèmes lors de la mise en œuvre de la solution de John Resig. Voici la fonction modifiée que j'ai utilisée en fonction de sa réponse:
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]) );
}
Cette approche plus robuste prend en compte la manière dont les utilisateurs envisagent d’utiliser ce type de saisie. Par exemple, si un utilisateur entre "12", il s’attend à ce que ce soit midi (12h) et non 12h. La fonction ci-dessous gère tout cela. Il est également disponible ici: 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() );
}
Ceci est un prototype de chaîne, vous pouvez donc l'utiliser comme suit:
var str = '12am';
var date = str.parseTime();
AnyTime.Converter peut analyser les dates/heures dans de nombreux formats différents:
Voici une solution plus pour tous ceux qui utilisent une horloge 24h qui prend en charge:
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]) );
}
Le paquet time a une taille de 0,9 Ko. Disponible avec les gestionnaires de package NPM et Bower.
Voici un exemple directement du 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
Voici une autre approche qui couvre la réponse originale, tout nombre raisonnable de chiffres, la saisie de données par les chats et les erreurs logiques. L'algorithme suit:
La conversion des heures, des minutes et de la publication de meridiem en un objet Date est un exercice pour le lecteur (de nombreuses autres réponses montrent comment faire cela).
"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() );
}
Avec jQuery, le prototype String nouvellement défini est utilisé comme suit:
<input type="text" class="time" />
$(".time").change( function() {
var $this = $(this);
$(this).val( time.toTime() );
});
J'ai apporté quelques modifications à la fonction ci-dessus pour prendre en charge quelques formats supplémentaires.
Ce n'est pas encore nettoyé, mais ça marche pour tout ce à quoi je peux penser.
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]) );
}
Si vous ne voulez que quelques secondes, voici une ligne.
const toSeconds = s => s.split(':').map(v => parseInt(v)).reverse().reduce((acc,e,i) => acc + e * Math.pow(60,i))
Une amélioration à la solution de Patrick McElhaney (sa gestion n'est pas correcte 12h)
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]) );
}
Beaucoup de réponses afin qu'un seul ne fera pas mal.
/**
* 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]) );
}
Pour être suffisamment robuste, il convient de vérifier que chaque valeur est dans la plage des valeurs autorisées, par exemple si am/pm hours doit être compris entre 1 et 12 inclus, sinon 0 à 24 inclus, etc.
/(\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 );
merci
Les autres réponses ne me satisfaisaient pas, alors j'en ai fait une autre. Cette version:
undefined
sur une entrée invalide telle que "13:00 pm" ou "11:65"localDate
, sinon renvoie une heure UTC sur l’époque Unix (1er janvier 1970).1330
(pour désactiver, faire le premier ':' requis dans la regex)^\s*
dans l'expression régulière)Edit: c'est maintenant un package incluant un formateur 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.');
Tableau de compilation d'autres réponses
Tout d’abord, je ne peux pas croire qu’il n’existe pas de fonctionnalité intégrée ni même de bibliothèque tierce robuste capable de gérer cela. En fait, c’est du développement web, donc je peux le croire.
Essayer de tester tous les cas Edge avec tous ces algorithmes différents me faisait tourner la tête. J'ai donc pris la liberté de compiler toutes les réponses et tous les tests de ce fil dans un tableau pratique.
Le code (et la table résultante) est inutile à inclure inline, j'ai donc créé un JSFiddle:
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
_ {Sentez-vous s'il vous plaît libre de bifurquer mon violon et d'ajouter plus d'algorithmes et de cas de tests}
Je n'ai pas ajouté de comparaison entre le résultat et la sortie "attendue", car il peut arriver que la sortie "attendue" puisse être débattue (par exemple, 12
devrait-il être interprété comme étant 12:00am
ou 12:00pm
?). Vous devrez parcourir la table et voir quel algorithme a le plus de sens pour vous.
Remarque: Les couleurs n'indiquent pas nécessairement la qualité ou "l'attente" de la sortie, elles indiquent uniquement le type de sortie:
red
= erreur js levée
yellow
= "falsy" value (undefined
, null
, NaN
, ""
, "invalid date"
)
green
= js Date()
object
light green
= tout le reste
Où un objet Date()
est la sortie, je le convertis au format HH:mm
24 h pour faciliter la comparaison.
Pourquoi ne pas utiliser la validation pour préciser ce qu'un utilisateur peut insérer et simplifier la liste pour inclure uniquement les formats pouvant être analysés (ou analysés après quelques ajustements).
Je ne pense pas que ce soit trop demander d'exiger d'un utilisateur de mettre une heure dans un format pris en charge.
dd: dd A (m)/P (m)
dd A (m)/P (m)
jj
Après des tests approfondis et une recherche approfondie dans mon autre réponse de compilation , j’ai conclu que la solution de @Dave Jarvis était la solution la plus proche de ce que j'estimais être des résultats raisonnables et une gestion des cas Edge. Pour référence, j'ai regardé ce que les entrées de temps de Google Agenda reformataient l'heure après avoir quitté la zone de texte.
Même quand même, j'ai vu qu'il ne traitait pas certains cas (bien que bizarres) d'Edge traités par Google Agenda. Alors je l'ai retravaillé de fond en comble et c'est ce que j'ai proposé. Je l'ai aussi ajouté à ma réponse à la compilation .
// attempt to parse string as time. return js date object
static 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;
}
Je pense que c’est ce qui me convient le mieux, mais les suggestions sont les bienvenues. Note: Ceci est centré sur l'Amérique en ce sens qu'il utilise par défaut am/pm pour certains modèles:
1
=> 13:00
(1:00pm
)1100
=> 23:00
(11:00pm
)456
=> 16:56
(4:56pm
)