Last active
February 14, 2020 08:45
-
-
Save mholtzhausen/e3be7035257611b4cf9a9e852c255b8c to your computer and use it in GitHub Desktop.
Date Formatting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const SECONDS = { | |
MINUTE: 60, | |
HOUR: 3600, | |
DAY: 86400, | |
WEEK: 604800, | |
MONTH: 2630016, //30.44 day month average | |
YEAR: 31557600, //based on 365.25 days per year | |
} | |
class DForm { | |
/** | |
* | |
* @param {Date} date | |
*/ | |
constructor(date) { | |
if (date instanceof DForm) return date | |
this.Year = date.getFullYear() | |
this.Month = date.getMonth() + 1 | |
this.Day = date.getDate() | |
this.Hour = date.getHours() | |
this.Minute = date.getMinutes() | |
this.Second = date.getSeconds() | |
this.Millisecond = date.getMilliseconds() | |
this.Weekday = date.getDay() | |
} | |
get DayOrd () { | |
let v = this.Day % 100; | |
let s = ["th", "st", "nd", "rd"] | |
return `${this.Day}${s[(v - 20) % 10] || s[v] || s[0]}` //stole this | |
} | |
get MonthPad () { return `${this.Month}`.padStart(2, '0') } | |
get DayPad () { return `${this.Day}`.padStart(2, '0') } | |
get HourPad () { return `${this.Hour}`.padStart(2, '0') } | |
get MinutePad () { return `${this.Minute}`.padStart(2, '0') } | |
get SecondPad () { return `${this.Second}`.padStart(2, '0') } | |
get Hour12 () { return `${this.Hour > 12 ? this.Hour % 12 : this.Hour}` } | |
get Hour12Pad () { return this.Hour12.padStart(2, '0') } | |
get AMPM () { return this.Hour >= 12 ? 'PM' : 'AM' } | |
get ampm () { return this.AMPM.toLowerCase() } | |
get MonthLong () { return ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][this.Month - 1] } | |
get MonthShort () { return ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][this.Month - 1] } | |
get DayLong () { return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][this.Weekday] } | |
get DayShort () { return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.Weekday] } | |
static parse (anyDate) { | |
if (!(anyDate instanceof Date)) anyDate = Date.parse(anyDate) | |
if (!anyDate) anyDate = new Date() | |
return new DForm(anyDate) | |
} | |
format (formatString) { | |
let formatted = `${formatString}` | |
let self = this | |
let matches = formatString.match(/\{([^\}]*)\}/g) || [] | |
matches.forEach(function(attr) { | |
let prop = `${attr}`.trim().split('').slice(1, attr.length - 1).join('') | |
if (prop in self) { | |
formatted = formatted.replace(attr, self[prop]) | |
} | |
}) | |
return formatted; | |
} | |
/** | |
* | |
* @param {Object} adjustment The required adjustment config eg {year:1, minute:-5} | |
*/ | |
adjust (adjustment = {}) { | |
adjustment = Object.assign({ years: 0, months: 0, days: 0, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }, adjustment || {}) | |
let d = this.date | |
d.setFullYear(d.getFullYear() + adjustment.years) | |
d.setMonth(d.getMonth() + adjustment.months) | |
d.setDate(d.getDate() + adjustment.days) | |
d.setHours(d.getHours() + adjustment.hours) | |
d.setMinutes(d.getMinutes() + adjustment.minutes) | |
d.setSeconds(d.getSeconds() + adjustment.seconds) | |
d.setMilliseconds(d.getMilliseconds() + adjustment.milliseconds) | |
return new DForm(d) | |
} | |
get date () { | |
return new Date(this.Year, this.Month - 1, this.Day, this.Hour, this.Minute, this.Second, this.Millisecond) | |
} | |
elapsed (date) { | |
if (date instanceof DForm) date = date.date | |
return Math.round((date.getTime() - this.date.getTime()) / 1000) | |
} | |
humanElapsed (date, max_seconds = 31557600, alt_format = null) { | |
let elapsed = this.elapsed(date) | |
let dir = elapsed < 0 ? ' ago' : ' from now' | |
elapsed = Math.abs(elapsed) | |
if (elapsed > max_seconds) return alt_format ? new DForm(date).format(alt_format) : null | |
let y = Math.floor(elapsed / SECONDS.YEAR) | |
let M = Math.floor(elapsed % SECONDS.YEAR / SECONDS.MONTH) | |
let d = Math.floor(elapsed % SECONDS.YEAR % SECONDS.MONTH / SECONDS.DAY) | |
let h = Math.floor(elapsed % SECONDS.YEAR % SECONDS.MONTH % SECONDS.DAY / SECONDS.DAY) | |
let m = Math.floor(elapsed % SECONDS.YEAR % SECONDS.MONTH % SECONDS.DAY % SECONDS.DAY / SECONDS.MINUTE) | |
let s = Math.floor(elapsed % SECONDS.YEAR % SECONDS.MONTH % SECONDS.DAY % SECONDS.DAY % SECONDS.MINUTE) | |
const dYears = () => [y ? `${y} years` : '', M ? `${M} months` : '', d ? `${d} days` : ''].filter(v => !!v).join(', ') + dir | |
const dMonths = () => [M ? `${M} months` : '', d ? `${d} days` : ''].filter(v => !!v).join(' and ') + dir | |
const dDays = () => [d ? `${d} days` : '', h ? `${h} hours` : ''].filter(v => !!v).join(', ') + dir | |
const dHours = () => [h ? `${h} hours` : '', m ? `${m} minutes` : ''].filter(v => !!v).join(' and ') + dir | |
const dMinutes = () => (m ? `${m} minutes` : '') + dir | |
const dSeconds = () => (s ? `${s} seconds` : '') + dir | |
if (y) return dYears() | |
if (M) return dMonths() | |
if (d) return dDays() | |
if (h) return dHours() | |
if (m) return dMinutes() | |
if (s) return dSeconds() | |
} | |
} | |
const DateFormats = { | |
HumanDate: '{Day} {MonthShort} {Year}', | |
HumanDateTime: '{Day} {MonthShort} {Year} at {Hour12}:{MinutePad} {ampm}', | |
HumanDateLong: '{DayLong}, {DayOrd} {MonthLong} {Year}', | |
HumanDateTimeLong: '{DayLong}, {DayOrd} {MonthLong} {Year} at {HourPad}h{MinutePad}', | |
ConciseDate: '{Day}-{Month}-{Year}', | |
ConciseDateTime: '{Day}-{Month}-{Year} {Hour}:{MinutePad}:{SecondPad}', | |
FormalDate: '{DayPad}/{MonthPad}/{Year}', | |
FormalDateTime: '{DayPad}/{MonthPad}/{Year} {HourPad}:{MinutePad}:{SecondPad}', | |
} | |
const rand = (min, max) => Math.trunc((Math.random() * (max - min + 1)) + min) | |
/** | |
* Testing | |
*/ | |
const date1 = new DForm(new Date()) | |
const date2 = date1.adjust({ days: -130, months: 0 }) | |
const date3 = date1.adjust({ months: rand(0, 2), days: rand(0, 40), hours: rand(0, 15) }) | |
/************************************************** | |
* DateFormats Test --- START | |
*************************Toggle with this space->* / | |
Object.keys(DateFormats).forEach(name => { | |
console.log(`${name}: `, date1.format(DateFormats[name])) | |
}) | |
/************************************************** | |
* DateFormats Test --- END | |
**************************************************/ | |
console.log('date1: ',date1.format(DateFormats.FormalDateTime)) | |
console.log('date2: ',date2.format(DateFormats.FormalDateTime)) | |
console.log('date3: ',date3.format(DateFormats.FormalDateTime)) | |
console.log() | |
console.log('date 2 elapsed seconds', date1.elapsed(date2)) | |
console.log('date 2 elapsed', date1.humanElapsed(date2)) | |
console.log('date 2 elapsed with short ttl:', date1.humanElapsed(date2, SECONDS.DAY * 5)) | |
console.log('date 2 elapsed with short ttl and alt format:', date1.humanElapsed(date2, SECONDS.DAY * 5, DateFormats.HumanDateTimeLong)) | |
console.log() | |
console.log('date 3 elapsed seconds', date1.elapsed(date3)) | |
console.log('date 3 elapsed', date1.humanElapsed(date3, SECONDS.YEAR * 3)) | |
console.log('date 3 elapsed with short ttl:', date1.humanElapsed(date3, SECONDS.DAY * 5)) | |
console.log('date 3 elapsed with short ttl and alt format:', date1.humanElapsed(date3, SECONDS.DAY * 5, DateFormats.HumanDateTimeLong)) | |
/************************************************** | |
* Export Section --- START | |
*************************Toggle with this space->* / | |
module.exports = { | |
DateFormats, | |
DForm, | |
SECONDS | |
} | |
/************************************************** | |
* Export Section --- END | |
**************************************************/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment