UNPKG

time-values

Version:

Gets date/time attributes from a date or string with no dependencies

117 lines (94 loc) 4.76 kB
const emptyObj = { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0 } const stringNums = (start = 0, end = 0) => Array.from(Array(end - start + 1), (_, i) => `${i + start}`) const getTimeValues = (inputDate = new Date()) => { if (!inputDate) { return { ...emptyObj } } // Assume this is a time-values output object, and fill in the blanks if (!(inputDate instanceof Date) && inputDate instanceof Object) { let year = inputDate.year == null ? new Date().getFullYear() : +inputDate.year let month = inputDate.month == null ? new Date().getMonth() + 1 : +inputDate.month let day = inputDate.day == null ? new Date().getDate() : +inputDate.day let hour = inputDate.hour == null ? new Date().getHours() : +inputDate.hour let minute = inputDate.minute == null ? new Date().getMinutes() : +inputDate.minute let second = inputDate.second == null ? new Date().getSeconds() : +inputDate.second // Loop around values out of range while (second >= 60) { second -= 60; minute++ } while (second < 0) { second += 60; minute-- } while (minute >= 60) { minute -= 60; hour++ } while (minute < 0) { minute += 60; hour-- } while (hour >= 24) { hour -= 24; day++ } while (hour < 0) { hour += 24; day-- } while (month > 12) { month -= 12; year++ } while (month < 1) { month += 12; year-- } // days are trickier because they're based off the days in a given month while (day > new Date(year, month, 0).getDate()) { day -= new Date(year, month, 0).getDate() month++ while (month > 12) { month -= 12; year++ } } while (day < 1) { month-- while (month < 1) { month += 12; year-- } day += new Date(year, month, 0).getDate() } return { year, month, day, hour, minute, second } } // String dates often have weird, special handling if (typeof inputDate === 'string') { // mm/dd/yyyy dates are a little wonky because they are always considered local tz, not UTC. if (/^\d{2}\/\d{2}\/\d{4}$/.test(inputDate)) { const [month, day, year] = inputDate.split('/') return { ...emptyObj, year: +year, month: +month, day: +day } } // ISO dates that don't specify a time should default to the start of the day // (amusingly this only applies for properly formatted ISO dates, so 2022-2-2 is fine) if (/^\d{4}\-\d{2}\-\d{2}$/.test(inputDate)) { const [year, month, day] = inputDate.split('-') return { ...emptyObj, year: +year, month: +month, day: +day } } // A year followed by a time value (separated by a 'T') if (/^\d{4}T/.test(inputDate)) { const [year, timeRaw] = inputDate.split('T') const [hour, minute, second] = timeRaw.split('.')[0].split(':').map(n => +n) return { year: +year, month: 1, day: 1, hour, minute, second } } // A year followed by a time value (separated by a ':') if (/^\d{4}:/.test(inputDate)) { const year = inputDate.substring(0, inputDate.indexOf(':')) const timeRaw = inputDate.substring(inputDate.indexOf(':') + 1) const [hour, minute, second] = timeRaw.split('.')[0].split(':').map(n => +n) return { year: +year, month: 1, day: 1, hour, minute, second } } // yyyy-mm with no day format defaults to the first of the month at hour 0 if (/^\d{4}-\d{2}$/.test(inputDate)) { const year = inputDate.substring(0, inputDate.indexOf('-')) const month = inputDate.substring(inputDate.indexOf('-') + 1) return { year: +year, month: +month, day: 1, hour: 0, minute: 0, second: 0 } } // When just 1-4 digits are specified if (/^\d?\d?\d?\d$/.test(inputDate)) { // Yeah, this is a thing if (inputDate === '0') { return { ...emptyObj, year: 2000, month: 1, day: 1 } } // As is this if (stringNums(1, 12).includes(inputDate) || stringNums(1, 12).map(s => `0${s}`).includes(inputDate)) { return { ...emptyObj, year: 2001, month: +inputDate, day: 1 } } // Anything else that is just up to 4 digits is a year return { ...emptyObj, year: +inputDate, month: 1, day: 1} } } const date = new Date(new Date(inputDate).getTime() - new Date(inputDate).getTimezoneOffset() * 6e4) const [dateRaw, timeRaw] = date.toISOString().split('T') const [year, month, day] = dateRaw.split('-').map(v => parseInt(v, 10)) const [hour, minute, second] = timeRaw.split('.')[0].split(':').map(n => +n) return { year, month: month, day, hour, minute, second } } getTimeValues.toDate = (timeValues) => { const p = s => `${s}`.padStart(2, '0') const t = getTimeValues(timeValues) return new Date(`${t.year}-${p(t.month)}-${p(t.day)}T${p(t.hour)}:${p(t.minute)}:${p(t.second)}`) } module.exports = getTimeValues