ما هي أفضل طريقة لتحليل الوقت في كائن التاريخ من إدخال المستخدم في Javascript؟

StackOverflow https://stackoverflow.com/questions/141348

سؤال

أنا أعمل على أداة نموذج للمستخدمين لإدخال وقت من اليوم في إدخال النص (لتطبيق التقويم).باستخدام JavaScript (نحن نستخدم jQuery FWIW)، أريد العثور على أفضل طريقة لتحليل النص الذي يُدخله المستخدم في JavaScript Date() كائن حتى أتمكن بسهولة من إجراء المقارنات وأشياء أخرى عليه.

حاولت parse() الطريقة وهي صعبة الإرضاء بعض الشيء بالنسبة لاحتياجاتي.أتوقع أن يكون قادرًا على تحليل أوقات إدخال الأمثلة التالية بنجاح (بالإضافة إلى تنسيقات الوقت الأخرى المشابهة منطقيًا) بنفس الطريقة Date() هدف:

  • 1:00 مساء
  • 1:00 مساء.
  • 1:00 ص
  • 1:00 مساء
  • 1:00 مساء.
  • 1:00 ص
  • 1 ظهرا
  • الساعة الواحدة بعد الظهر
  • 1 ص
  • الساعة الواحدة بعد الظهر
  • الساعة الواحدة ظهرًا
  • 1 ص
  • 13:00
  • 13

أفكر في أنني قد أستخدم التعبيرات العادية لتقسيم المدخلات واستخراج المعلومات التي أريد استخدامها لإنشاء ملفي Date() هدف.ما هي أفضل طريقة للقيام بذلك؟

هل كانت مفيدة؟

المحلول

حل سريع يعمل على المدخلات التي حددتها:

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 صباحًا، وما إلى ذلك.

نصائح أخرى

جميع الأمثلة المقدمة تفشل في العمل للأوقات من 12:00 صباحًا إلى 12:59 صباحًا.كما أنهم يرتكبون خطأً إذا كان التعبير العادي لا يتطابق مع الوقت.ما يلي يعالج هذا:

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 ظهرًا.إذا كانت النتيجة المرغوبة هي أنها تُرجع فقط الوقت الذي تحتوي فيه السلسلة فقط على وقت، فيمكن استخدام التعبير العادي التالي بشرط استبدال "time[4]" بـ "time[6]".

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

لا تهتم بفعل ذلك بنفسك، فقط استخدمه datejs.

تؤدي معظم حلول التعبير العادي هنا إلى حدوث أخطاء عندما لا يمكن تحليل السلسلة، ولا يمثل الكثير منها سلاسل مثل 1330 أو 130pm.على الرغم من أن هذه التنسيقات لم يتم تحديدها بواسطة OP، إلا أنني أجدها ضرورية لتحليل إدخال التواريخ بواسطة البشر.

كل هذا دفعني إلى التفكير في أن استخدام التعبير العادي قد لا يكون أفضل طريقة لتحقيق ذلك.

الحل الخاص بي هو وظيفة لا تقوم بتوزيع الوقت فحسب، بل تسمح لك أيضًا بتحديد تنسيق الإخراج وخطوة (فاصل زمني) لتقريب الدقائق إليها.عند حوالي 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]) );
}

وهنا تحسن على نسخة جو.لا تتردد في تعديله بشكل أكبر.

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 مساءً" مثل "2:23 مساءً"

لقد واجهت بعض مكامن الخلل في تنفيذ حل 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]) );
}

يستطيع AnyTime.Converter تحليل التواريخ/الأوقات بعدة تنسيقات مختلفة:

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

ال وقت حجم الحزمة 0.9 كيلو بايتمتوفر مع مديري الحزم NPM وbower.

إليك مثال مباشرة من 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

يعد هذا أسلوبًا أكثر صرامة يأخذ في الاعتبار كيف ينوي المستخدمون استخدام هذا النوع من المدخلات.على سبيل المثال، إذا أدخل المستخدم "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();

فيما يلي حل أكثر لجميع أولئك الذين يستخدمون ساعة 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]) );
}

لقد قمت بإجراء بعض التعديلات على الوظيفة أعلاه لدعم المزيد من التنسيقات.

  • 1400 -> 2:00 ظهرًا
  • 1.30 -> 1:30 مساءً
  • 1:30 صباحًا -> 1:30 صباحًا
  • 100 -> 1: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]) );
}

إليك طريقة أخرى تغطي الإجابة الأصلية وأي عدد معقول من الأرقام وإدخال البيانات بواسطة القطط والمغالطات المنطقية.الخوارزمية التالية:

  1. تحديد ما إذا كان الزوال هو بعد الظهر.
  2. تحويل أرقام الإدخال إلى قيمة عددية.
  3. الوقت بين 0 و 24:الساعة هي الساعة ظهرًا، ولا توجد دقائق (الساعة 12 هي الساعة ظهرًا).
  4. الوقت بين 100 و 2359:الساعات div 100 هي الساعة، والدقائق mod 100 المتبقية.
  5. الوقت من 2400 على:الساعة منتصف الليل، وتبقى دقائق.
  6. عندما تتجاوز الساعات 12، اطرح 12 وافرض ما بعد خط الطول على الصحيح.
  7. عندما تتجاوز الدقائق 59، اجبر على 59.

يعد تحويل الساعات والدقائق وما بعد الزوال إلى كائن التاريخ بمثابة تمرين للقارئ (توضح العديد من الإجابات الأخرى كيفية القيام بذلك).

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

لماذا لا تستخدم التحقق من الصحة لتضييق نطاق ما يمكن للمستخدم وضعه وتبسيط القائمة لتشمل فقط التنسيقات التي يمكن تحليلها (أو تحليلها بعد بعض التغيير والتبديل).

لا أعتقد أن مطالبة المستخدم بتحديد وقت بتنسيق مدعوم أمر مبالغ فيه.

ي ي: ي ي أ(م)/ف(م)

د أ(م)/ف(م)

د

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

شكرًا

هناك الكثير من الإجابات حتى لا يضر واحد آخر.

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

لكي تكون قوية بشكل صحيح، يجب التحقق من أن كل قيمة تقع ضمن نطاق القيم المسموح بها، على سبيل المثال، إذا كانت ساعات الصباح/المساء يجب أن تكون من 1 إلى 12 ضمناً، وإلا من 0 إلى 24 ضمناً، وما إلى ذلك.

تحسين لحل باتريك ماكلهاني (لا يتعامل مع الساعة 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]) );
}

لم أكن سعيدًا بالإجابات الأخرى، لذا قمت بإعداد إجابات أخرى.هذه النسخة:

  • يتعرف على الثواني والميلي ثانية
  • عائدات undefined عند إدخال غير صالح مثل "13:00 مساءً" أو "11:65"
  • إرجاع التوقيت المحلي إذا قمت بتوفير localDate المعلمة، وإلا فإنها تُرجع وقت UTC في عصر Unix (1 يناير 1970).
  • يدعم الوقت العسكري مثل 1330 (للتعطيل، قم بإجراء أول ':' مطلوب في التعبير العادي)
  • يسمح بساعة بمفردها، مع وقت 24 ساعة (أي."7" تعني 7 صباحًا).
  • يسمح بالساعة 24 كمرادف للساعة 0، لكن الساعة 25 غير مسموح بها.
  • يتطلب الوقت ليكون في بداية السلسلة (للتعطيل، الإزالة ^\s* في التعبير العادي)
  • يحتوي على رمز اختبار يكتشف فعليًا عندما يكون الإخراج غير صحيح.

يحرر:انها الآن أ طَرد بما في ذلك 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.');

إذا كنت تريد ثوانٍ فقط، فإليك بطانة واحدة

const toSeconds = s => s.split(':').map(v => parseInt(v)).reverse().reduce((acc,e,i) => acc + e * Math.pow(60,i))

جدول تجميع الإجابات الأخرى

الأول على الجميع لا أصدق أنه لا توجد وظيفة مضمنة أو حتى مكتبة خارجية قوية يمكنها التعامل مع هذا الأمر.في الواقع، إنه تطوير ويب لذا يمكنني أن أصدق ذلك.

كانت محاولة اختبار جميع الحالات المتطورة باستخدام كل هذه الخوارزميات المختلفة تجعل رأسي يدور، لذلك أخذت الحرية في تجميع جميع الإجابات والاختبارات في هذا الموضوع في جدول مفيد.

الكود (والجدول الناتج) كبير جدًا بحيث لا يمكن تضمينه في السطر، لذلك قمت بإنشاء 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

من فضلك لا تتردد في شوكة كماني وإضافة المزيد من الخوارزميات وحالات الاختبار

لم أقم بإضافة أي مقارنات بين النتيجة والمخرجات "المتوقعة"، لأن هناك حالات يمكن فيها مناقشة المخرجات "المتوقعة" (على سبيل المثال، هل ينبغي 12 يمكن تفسيرها على أنها 12:00am أو 12:00pm؟).سيتعين عليك مراجعة الجدول ومعرفة الخوارزمية الأكثر منطقية بالنسبة لك.

ملحوظة: لا تشير الألوان بالضرورة إلى جودة المخرجات أو "توقعاتها"، فهي تشير فقط إلى نوع المخرجات:

  • red = ألقيت خطأ شبيبة

  • yellow = القيمة "خاطئة" (undefined, null, NaN, "", "invalid date")

  • green = شبيبة Date() هدف

  • light green = كل شيء آخر

اين ا Date() الكائن هو الإخراج، وأنا تحويله إلى 24 ساعة HH:mm شكل لسهولة المقارنة.

بعد الاختبار الدقيق والتحقيق من خلال إجابتي التجميعية الأخرى, ، خلصت إلى أن حل @Dave Jarvis كان الأقرب إلى ما شعرت أنه مخرجات معقولة ومعالجة لحالة الحافة.كمرجع، لقد ألقيت نظرة على ما تم إعادة تنسيق الوقت إليه من خلال إدخالات تقويم Google بعد الخروج من مربع النص.

ومع ذلك، رأيت أنه لم يتعامل مع بعض حالات الحافة (وإن كانت غريبة) التي قام بها تقويم Google.لذلك قمت بإعادة صياغتها من الألف إلى الياء وهذا ما توصلت إليه.لقد أضفته أيضًا إلى إجابتي التجميعية.

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

أشعر أن هذا هو أقرب ما يمكنني الحصول عليه لتلبية احتياجاتي، ولكن الاقتراحات مرحب بها. ملحوظة: هذا أمر متمركز حول أمريكا حيث يتم تعيينه افتراضيًا على صباحًا/مساءً لأنماط معينة:

  • 1 => 13:00 (1:00pm)
  • 1100 => 23:00 (11:00pm)
  • 456 => 16:56 (4:56pm)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top