Nice programing

Javascript의 사용자 입력에서 Date 객체로 시간을 구문 분석하는 가장 좋은 방법은 무엇입니까?

nicepro 2020. 11. 22. 20:32
반응형

Javascript의 사용자 입력에서 Date 객체로 시간을 구문 분석하는 가장 좋은 방법은 무엇입니까?


사용자가 텍스트 입력 (캘린더 응용 프로그램의 경우)에 시간을 입력 할 수있는 양식 위젯을 작업 중입니다. JavaScript (우리는 jQuery FWIW를 사용하고 있음)를 사용하여 사용자가 JavaScript Date()개체에 입력 한 텍스트를 구문 분석하여 쉽게 비교 및 ​​기타 작업을 수행 할 수있는 가장 좋은 방법을 찾고 싶습니다 .

나는 parse()방법을 시도 했고 그것은 내 필요에 대해 너무 까다 롭습니다. 다음 예제 입력 시간 (다른 논리적으로 유사한 시간 형식과 함께)을 동일한 Date()객체 로 성공적으로 구문 분석 할 수있을 것으로 기대 합니다.

  • 오후 1:00
  • 오후 1:00
  • 1 : 00p
  • 1:00 pm
  • 1:00 p.m.
  • 1 : 00p
  • 오후 1시
  • 오후 1시
  • 1p
  • 오후 1시
  • 오후 1시.
  • 1p
  • 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]) );
}

다른 몇 가지 품종에서도 작동해야합니다 (예를 들어 am을 사용하더라도 여전히 작동합니다). 분명히 이것은 매우 조잡하지만 꽤 가볍습니다 (예를 들어 전체 라이브러리보다 사용하는 것이 훨씬 저렴합니다).

경고 : 코드는 오전 12시 등에서는 작동하지 않습니다.


제공된 모든 예제는 오전 12 시부 터 오전 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]) );
}


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 () 호출에 radix 매개 변수를 추가했습니다 (따라서 jslint가 불평하지 않습니다).
  • 정규식을 대소 문자를 구분하지 않으므로 "2:23 PM"이 "2:23 pm"처럼 작동합니다.

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.9kbs입니다. 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 PM
  • 1 : 30a-> 1:30 AM
  • 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은시, 분 모드 100 나머지입니다.
  5. 2400부터 시작 : 시간은 자정이고 나머지는 분입니다.
  6. 시간이 12를 초과하면 12를 빼고 post meridiem을 true로 설정합니다.
  7. 분이 59를 초과하면 59로 강제 설정합니다.

시간, 분 및 포스트 메리 디엠을 Date 객체로 변환하는 것은 독자를위한 연습입니다 (이를 수행하는 방법을 보여주는 다른 답변이 많이 있습니다).

"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에서 새로 정의 된 String 프로토 타입은 다음과 같이 사용됩니다.

  <input type="text" class="time" />
  $(".time").change( function() {
    var $this = $(this);
    $(this).val( time.toTime() );
  });

유효성 검사를 사용하여 사용자가 입력 할 수있는 항목의 범위를 좁히고 구문 분석 할 수있는 형식 만 포함하도록 목록을 단순화하는 것은 어떻습니까 (또는 일부 조정 후 구문 분석).

사용자에게 지원되는 형식으로 시간을 투자하도록 요구하는 것이 너무 많이 요구되지 않는다고 생각합니다.

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

감사


답변이 많으므로 한 번 더해도 아프지 않습니다.

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

적절하게 견고 해지려면 각 값이 허용 된 값 범위 내에 있는지 확인해야합니다. 예를 들어 am / pm 시간이 1에서 12까지, 그렇지 않으면 0에서 24까지 포함해야합니다.


Patrick McElhaney의 솔루션 개선 (12am을 올바르게 처리하지 못함)

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 pm"또는 "11:65"와 같은 잘못된 입력을 반환합니다 .
  • localDate매개 변수 를 제공하면 현지 시간을 반환하고 , 그렇지 않으면 Unix 시대 (1970 년 1 월 1 일)의 UTC 시간을 반환합니다.
  • 다음과 같은 군사 시간을 지원합니다 1330(비활성화하려면 정규식에 첫 번째 ':'이 필요함)
  • 24 시간 제로 1 시간 만 허용됩니다 (예 : "7"은 오전 7시를 의미 함).
  • 시간 0의 동의어로 24 시간을 허용하지만 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.');

몇 초만 원하시면 여기에 1 개의 라이너가 있습니다.

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:00am12:00pm

참고 : 색상이 반드시 출력의 품질 또는 "예상"을 나타내는 것은 아니며 출력 유형 만 나타냅니다.

  • red = js 오류 발생

  • yellow= "falsy"값 ( undefined, null, NaN, "", "invalid date")

  • green= js 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;
}

나는 이것이 나의 필요에 가장 가깝다고 생각하지만 제안은 환영합니다. 참고 : 이것은 특정 패턴에 대해 기본값이 am / pm이라는 점에서 미국 중심입니다.

  • 1=> 13:00( 1:00pm)
  • 1100=> 23:00( 11:00pm)
  • 456=> 16:56( 4:56pm)

참고URL : https://stackoverflow.com/questions/141348/what-is-the-best-way-to-parse-a-time-into-a-date-object-from-user-input-in-javas

반응형