import isString from 'lodash/isString';
import isEmpty from 'lodash/isEmpty';
import moment from 'moment';
import NumberUtils from 'number-utils';
import StringUtils from 'string-utils';
import SHGlobals from 'sh-globals';
/**
* Utilities for working with times.
* @module TimeUtils
*/
const TimeUtils = {
/**
* Normalizes the provided time down to the provided step.
* @static
* @function normalizeToStep
* @param {String} time - The input value in the format hh:mm A.
* @param {Number} [step=1] - The step to round down to.
* @example
* TimeUtils.normalizeToStep('07:07 PM', 15); // '07:00 PM'
* @returns {String} - The normalized time.
*/
normalizeToStep(time, step = 1) {
if (isEmpty(time)) { return time; }
if (!isString(time)) {
throw new Error('The supplied time is not a string.');
}
const {hours, mins} = TimeUtils.getValuesFromString(time, step);
return TimeUtils.getFromValuesAsString(hours, mins);
},
/**
* Provides the hours, minutes, and meridiem from a time string.
* @static
* @function getValuesFromString
* @param {String} time - The input value in the format hh:mm A.
* @param {Number} [step=1] - The step to round down to.
* @example
* TimeUtils.getValuesFromString('10:19 AM');
* @returns {Object} - The object containing the hours, minutes, and meridiem.
*/
getValuesFromString(time, step = 1) {
if (isEmpty(time)) { return time; }
if (!isString(time)) {
throw new Error('The supplied time is not a string.');
}
const firstPartials = time.split(':');
const secondPartials = firstPartials[1].split(' ');
const isAM = secondPartials[1] === 'AM';
const mins = parseInt(secondPartials[0], 10);
const minsRounded = NumberUtils.roundDownToNearestStep(mins, step);
let hours = parseInt(firstPartials[0], 10);
if (isAM && hours === 12) {
hours = 0;
} else if (!isAM && hours !== 12) {
hours += 12;
}
return {
hours,
mins: minsRounded,
isAM
};
},
/**
* Provides the formatted time from hours and minutes values.
* @static
* @function getFromValuesAsString
* @param {Number} hours - The hours in a 24 hour format.
* @param {Number} minutes - The minutes from 0 - 60.
* @param {Boolean} [roundMinutesDown=false] - Whether to round the minutes down to the provided step.
* @param {Number} [step=1] - The step to round minutes down to.
* @example
* TimeUtils.getFromValuesAsString(20, 35); // '08:35 PM'
* @returns {String} - The formatted time.
*/
getFromValuesAsString(hours, minutes, roundMinutesDown = false, step = 1) {
const meridiem = (hours < 12) ? 'AM' : 'PM';
if (hours > 12) {
hours -= 12;
} else if (hours === 0) {
hours = 12;
}
if (roundMinutesDown) {
minutes = NumberUtils.roundDownToNearestStep(minutes, step);
}
return `${StringUtils.pad(hours)}:${StringUtils.pad(minutes)} ${meridiem}`;
},
/**
* Converts a mobile input time to a string in the format hh:mm A.
* @static
* @function getMobileAsString
* @param {String} time - The input value in the format HH:mm (24 hour format).
* @param {Number} [step=1] - The step to round down to.
* @example
* TimeUtils.getMobileAsString('22:19'); // 10:19 PM
* @returns {String} - The formatted time.
*/
getMobileAsString(time, step = 1) {
if (!isString(time)) {
throw new Error('The supplied time is not a string.');
}
const frags = time.split(':');
const mins = parseInt(frags[1], 10);
const minsRounded = NumberUtils.roundDownToNearestStep(mins, step);
const hours = parseInt(frags[0], 10);
const meridiem = (hours < 12) ? 'AM' : 'PM';
let hh = hours;
if (hours > 12) {
hh -= 12;
} else if (hours === 0) {
hh = 12;
}
return `${StringUtils.pad(hh)}:${StringUtils.pad(minsRounded)} ${meridiem}`;
},
/**
* Converts a time to a date object.
* @static
* @function getAsDate
* @param {String} time - The input value in the format hh:mm A.
* @example
* TimeUtils.getAsDate('10:19 PM');
* @returns {Date} - The time inside of a date object.
*/
getAsDate(time) {
if (isEmpty(time)) { return null; }
if (!isString(time)) {
throw new Error('The supplied time is not a string.');
}
const {hours, mins} = TimeUtils.getValuesFromString(time);
let d = new Date();
d.setHours(hours);
d.setMinutes(mins);
d.setSeconds(0);
return d;
},
/**
* Converts a time to a moment instance.
* @static
* @function getAsMoment
* @param {String} time - The input value in the format hh:mm A.
* @example
* TimeUtils.getAsMoment('10:19 PM');
* @returns {Moment} - The time inside of a moment instance.
*/
getAsMoment(time) {
if (isEmpty(time)) { return null; }
if (!isString(time)) {
throw new Error('The supplied time is not a string.');
}
const {hours, mins} = TimeUtils.getValuesFromString(time);
return moment().startOf('day').add(hours, 'hours').add(mins, 'minutes');
},
/**
* Generate an array of times.
* @static
* @function getTimes
* @param {Object} data - The data to pass to the function.
* @param {Number} [data.step=30] - Increment times by this many minutes.
* @param {String} [data.format='hh:mm A'] - Moment.js format (http://momentjs.com/docs/#/displaying/format/).
* @example
* TimeUtils.getTimes({
* step: 30,
* format: 'hh:mm A'
* });
* @returns {Array} times - An array of times.
*/
getTimes({step = 30, format = SHGlobals.DESKTOP_TIME_FORMAT}) {
const total = 1440;
const len = (total / step);
const times = [];
let i = 0;
let id = 0;
for (i; i < len; i++) {
id = (i * step);
const time = moment().startOf('day').add(id, 'minutes');
times.push({
id: id,
formatted: time.format(format)
});
}
return times;
}
};
export default TimeUtils;