JSFiddle - React, Tailwind, and code Playground

by Josh Pullen

JavaScript

class Duration {
  constructor({
  	years = 0,
    months = 0,
    weeks = 0,
    days = 0,
    hours = 0,
    minutes = 0,
    seconds = 0
  }) {
  	this.years = years
    this.months = months
    this.days = days + 7 * weeks
    this.hours = hours
    this.minutes = minutes
    this.seconds = seconds
  }
  
  static fromLiteral(str) {
    const tokens = str
      .split(/(\d+)/g)
      .map(s => s.trim())
      .filter(s => s !== '')
      .map(item => {
        const unitAliases = {
          years: 'years',
          year: 'years',
          y: 'years',
          months: 'months',
          month: 'months',
          weeks: 'weeks',
          week: 'weeks',
          w: 'weeks',
          days: 'days',
          day: 'days',
          d: 'days',
          hours: 'hours',
          hour: 'hours',
          h: 'hours',
          minutes: 'minutes',
          minute: 'minutes',
          mins: 'minutes',
          min: 'minutes',
          m: 'minutes',
          seconds: 'seconds',
          second: 'seconds',
          secs: 'seconds',
          sec: 'seconds',
          s: 'seconds'
        }

        if (unitAliases[item]) {
          return { type: 'unit', unit: unitAliases[item] }
        }

        return { type: 'number', num: parseInt(item, 10) }
      })
    
    if (tokens.length % 2 !== 0) return null
    
    let values = { years: 0, months: 0, days: 0, hours: 0, minutes: 0, seconds: 0 }
    let usedUnits = []
    for (let i = 0; i < tokens.length; i += 2) {
    	if (tokens[i].type !== 'number') return null
      if (tokens[i + 1].type !== 'unit') return null
      
      const unit = tokens[i + 1].unit
      const num = tokens[i].num
      
      // Reject if a single unit is being defined twice
      if (usedUnits.includes(unit)) {
      	return null
      }
      
      if (unit === 'weeks') {
      	values.days += 7 * num
      } else {
        values[unit] += num
      }
      
      usedUnits.push(unit)
    }
    
    return new this(values)
 ...