function time12hToDayfraction(input) {
if ( typeof input !== 'string') throw TypeError('Invalid type. Expexted string');
// Using regex validate a valid time and to split it into hours, minutes and AM/PM
// ^ Match start of string
// (1[0-2]|[0-9]) Match 1 follwed by a 0,1 or 2, or 0,1,2,3,4,5,6,7,8 or 9
// : Match the colon
// ([0-5][0-9]) Match 0,1,2,3,4 or 5 followed by 0,1,2,3,4,5,6,7,8 or 9.
// ([AP]M) Match A or P followed by M
// $ Match end of string
// toUpperCase converts the string to upper case. I could have made the regex
// case insensitive, but when calculating the hours below I need to know if
// if was AM or PM, and now I can make a simple string comparison instead of
// a case insensitive comparison.
const parts = input.toUpperCase().match(/^(1[0-2]|[0-9]):([0-5][0-9]) ([AP]M)$/);
if (!parts) throw Error('Invalid format');
// Convert string in parts to numbers
const value = {
// parts[1] is the hours.
// parts[2] is the minutes
// parts[3] is "AM" or "PM"
// Using reminder % to make 12 = 0.
// Using conditional (ternary) operator to decide if 0 or 12 should be added.
hours : ( +parts[1] % 12 ) + ( parts[3] === 'PM' ? 12 : 0 ), // Convert to 24 hours
minutes : +parts[2]
}
// This returns MIDNIGHT (12:00 AM) as 0, and NOON (12:00 PM) as 0.5
return ( value.hours + ( value.minutes / 60 ) ) / 24
// I saw that you example had "12:00 AM" as 1. If you want "12:00 AM" as 1,
// and "12:01 AM" as slmost zero, replace the line above with:
// return (( value.hours + ( value.minutes / 60 ) ) / 24) || 1
}
// Converts a day fraction to time 12 h
function dayFractionToTime12h(input) {
if ( typeof input !== 'number') throw TypeError('Invalid type. Expexted number');
if ( input < 0 || input > 1 ) throw RangeError('Input shuld be 0 - 1');
const clock24 = input * 24; // Convert input to 24 hour clock.
const value = {
// Convert 24-hour-clock to 12-hour-clock by using
// reminder % 12 to get a value between 0-11 and locical or-operator
// to convert 0 to 12.
hours : (Math.floor( clock24 ) % 12) || 12,
// Calculate minutes
minutes : Math.round(clock24 * 60) % 60,
apm : clock24 < 12 ? 'AM' : 'PM'
}
return `${value.hours}:${value.minutes.toString().padStart(2,'0')} ${value.apm}`;
}
// Example
[
'12:00 AM', '12:30 AM', '1:00 AM', '2:00 AM', '3:00 AM', '4:00 AM', '5:00 AM',
'6:00 AM', '7:00 AM', '8:00 AM', '9:00 AM', '10:00 AM', '11:00 AM',
'12:00 PM', '1:00 PM', '2:00 PM', '3:00 PM', '4:00 PM', '5:00 PM',
'6:00 PM', '7:00 PM', '8:00 PM', '9:00 PM', '10:00 PM', '11:00 PM',
'11:59 PM'
].forEach( input => {
const frac = time12hToDayfraction(input);
const time = dayFractionToTime12h(frac);
if (input != time) throw Error(`input!=time "${input}" "${time}"`);
console.log( input, frac.toFixed(2), time );
});