Skip to content

Commit

Permalink
Add fullTimeAgo function to calculate time duration in various units (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
NatoBoram authored Nov 26, 2023
1 parent 016def4 commit a5a815a
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/node.js.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ jobs:
- run: pnpm run build
- run: pnpm run check
- run: pnpm run lint
- run: pnpm run test:unit
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ vite.config.ts.timestamp-*

# Example data
/examples/my_user.json

# Bun
bun.lockb
37 changes: 37 additions & 0 deletions src/lib/utils/dates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, test } from 'vitest'
import { fullTimeAgo, timeAgo } from './dates'

describe('timeAgo', () => {
test('just now', ({ expect }) => expect(timeAgo(new Date())).toBe('just now'))

test('in the future', ({ expect }) => {
const date = new Date(8640000000000000)
expect(timeAgo(date)).toBe('in the future')
})

test('2 subepochs ago', ({ expect }) => {
const date = new Date(-8640000000000000)
expect(timeAgo(date)).toBe('2 subepochs ago')
})
})

describe('fullTime', () => {
test('min date', ({ expect }) => {
const date = new Date(-8640000000000000)
expect(fullTimeAgo(date)).toBeTypeOf('string')
})

test('in the future', ({ expect }) => {
const date = new Date(8640000000000000)
expect(fullTimeAgo(date)).toBe('in the future')
})

test('1h 2m 3s ago', ({ expect }) => {
const date = new Date()
date.setHours(date.getHours() - 1)
date.setMinutes(date.getMinutes() - 2)
date.setSeconds(date.getSeconds() - 3)

expect(fullTimeAgo(date)).toBe('1 hour 2 minutes 3 seconds ago')
})
})
132 changes: 132 additions & 0 deletions src/lib/utils/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,135 @@ export function timeAgo(date: Date) {
const eons = Math.floor(duration.to(durationUnit.eon).value)
return `${eons} ${eons === 1 ? 'eon' : 'eons'} ago`
}

export function fullTimeAgo(date: Date) {
const now = new Date()
const milliseconds = now.getTime() - date.getTime()

if (milliseconds < 0) return 'in the future'

let duration = new Duration(milliseconds, durationUnit.millisecond)
const result = []

const eons = duration.to(durationUnit.eon).value
if (eons >= 1) {
const floor = Math.floor(eons)
result.push(`${floor} ${floor === 1 ? 'eon' : 'eons'}`)
duration = duration.minus(new Duration(floor, durationUnit.eon))
}

const eras = duration.to(durationUnit.era).value
if (eras >= 1) {
const floor = Math.floor(eras)
result.push(`${floor} ${floor === 1 ? 'era' : 'eras'}`)
duration = duration.minus(new Duration(floor, durationUnit.era))
}

const periods = duration.to(durationUnit.period).value
if (periods >= 1) {
const floor = Math.floor(periods)
result.push(`${floor} ${floor === 1 ? 'period' : 'periods'}`)
duration = duration.minus(new Duration(floor, durationUnit.period))
}

const epochs = duration.to(durationUnit.epoch).value
if (epochs >= 1) {
const floor = Math.floor(epochs)
result.push(`${floor} ${floor === 1 ? 'epoch' : 'epochs'}`)
duration = duration.minus(new Duration(floor, durationUnit.epoch))
}

const subepochs = duration.to(durationUnit.subepoch).value
if (subepochs >= 1) {
const floor = Math.floor(subepochs)
result.push(`${floor} ${floor === 1 ? 'subepoch' : 'subepochs'}`)
duration = duration.minus(new Duration(floor, durationUnit.subepoch))
}

const ages = duration.to(durationUnit.age).value
if (ages >= 1) {
const floor = Math.floor(ages)
result.push(`${floor} ${floor === 1 ? 'age' : 'ages'}`)
duration = duration.minus(new Duration(floor, durationUnit.age))
}

const millennia = duration.to(durationUnit.millennium).value
if (millennia >= 1) {
const floor = Math.floor(millennia)
result.push(`${floor} ${floor === 1 ? 'millennium' : 'millennia'}`)
duration = duration.minus(new Duration(floor, durationUnit.millennium))
}

const centuries = duration.to(durationUnit.century).value
if (centuries >= 1) {
const floor = Math.floor(centuries)
result.push(`${floor} ${floor === 1 ? 'century' : 'centuries'}`)
duration = duration.minus(new Duration(floor, durationUnit.century))
}

const decades = duration.to(durationUnit.decade).value
if (decades >= 1) {
const floor = Math.floor(decades)
result.push(`${floor} ${floor === 1 ? 'decade' : 'decades'}`)
duration = duration.minus(new Duration(floor, durationUnit.decade))
}

const years = duration.to(durationUnit.year).value
if (years >= 1) {
const floor = Math.floor(years)
result.push(`${floor} ${floor === 1 ? 'year' : 'years'}`)
duration = duration.minus(new Duration(floor, durationUnit.year))
}

const months = duration.to(durationUnit.month).value
if (months >= 1) {
const floor = Math.floor(months)
result.push(`${floor} ${floor === 1 ? 'month' : 'months'}`)
duration = duration.minus(new Duration(floor, durationUnit.month))
}

const weeks = duration.to(durationUnit.week).value
if (weeks >= 1) {
const floor = Math.floor(weeks)
result.push(`${floor} ${floor === 1 ? 'week' : 'weeks'}`)
duration = duration.minus(new Duration(floor, durationUnit.week))
}

const days = duration.to(durationUnit.day).value
if (days >= 1) {
const floor = Math.floor(days)
result.push(`${floor} ${floor === 1 ? 'day' : 'days'}`)
duration = duration.minus(new Duration(floor, durationUnit.day))
}

const hours = duration.to(durationUnit.hour).value
if (hours >= 1) {
const floor = Math.floor(hours)
result.push(`${floor} ${floor === 1 ? 'hour' : 'hours'}`)
duration = duration.minus(new Duration(floor, durationUnit.hour))
}

const minutes = duration.to(durationUnit.minute).value
if (minutes >= 1) {
const floor = Math.floor(minutes)
result.push(`${floor} ${floor === 1 ? 'minute' : 'minutes'}`)
duration = duration.minus(new Duration(floor, durationUnit.minute))
}

const seconds = duration.to(durationUnit.second).value
if (seconds >= 1) {
const floor = Math.floor(seconds)
result.push(`${floor} ${floor === 1 ? 'second' : 'seconds'}`)
duration = duration.minus(new Duration(floor, durationUnit.second))
}

const rest = duration.to(durationUnit.millisecond).value
if (rest >= 1) {
const floor = Math.floor(rest)
result.push(`${floor} ${floor === 1 ? 'millisecond' : 'milliseconds'}`)
duration = duration.minus(new Duration(floor, durationUnit.millisecond))
}

result.push('ago')
return result.join(' ')
}
8 changes: 8 additions & 0 deletions src/lib/utils/duration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { test } from 'vitest'
import { Duration, durationUnit } from './duration'

test('MAX_SAFE_INTEGER', ({ expect }) => {
const duration = new Duration(Number.MAX_SAFE_INTEGER, durationUnit.millisecond)
const subepochs = duration.to(durationUnit.subepoch).value
expect(subepochs).toBe(2.8542678186223407)
})

0 comments on commit a5a815a

Please sign in to comment.