timelang - Natural Language Time Parser for JavaScript

2 min read Original article ↗

Parse time, naturally

Human-friendly time expressions → JavaScript Dates

A few examples of what you can parse. See the docs below for details.

Dates

today, tomorrow, yesterday

next monday at 3pm

march 15th, the 20th

day after tomorrow

third Thursday of November

last day of march

Durations

2 days, 3 weeks, 1 month

1d, 2w, 3mo, 1y, 2h, 30m

half a day, 1.5 weeks

1 week and 2 days

two and a half hours

a couple of days

Spans

jan 5 to jan 20

last 30 days, next 2 weeks

july 3rd for 10 days

this week, this month, ytd

jan through mar

monday through friday

Fuzzy Periods

Q1, Q1 2025, first quarter

early january, mid Q1

H1 2025, H2 2025

spring, summer, winter

beginning of month

end of year, start of week

Business

next business day

in 5 business days

EOD, COB, EOD Friday

close of business Monday

end of day tomorrow

2 business days ago

Natural Time

half past 4, quarter to 5

noon on Friday, midnight

in a fortnight

week 12, the week of March 15

10 to noon, 5 past 3pm

tomorrow half past 9

npm install @timelang/parse

Usage

Use parse() for automatic type detection, or one of the specific functions if you know what to expect.

import { parse } from '@timelang/parse'

parse('next friday')

parse('tomorrow at 3pm')

parse('march 15th 2025')

parse('2 weeks')

parse('1h 30m')

parse('jan 5 to jan 20')

parse('last 30 days')

parse('next monday for 2 weeks')

parse('Team offsite - March 10 to March 14')

parse('Sprint 1: jan 5 to jan 19')

parse('Q1 2025')

parse('early january')

parse('mid Q1')

Helpers

import { parseDate, parseDuration, parseSpan, scan } from '@timelang/parse'

parseDate('tomorrow')

parseDate('next friday at 3pm')

parseDate('in 2 hours')

parseDuration('2 weeks')

parseDuration('2h 30m')

parseSpan('jan 5 to jan 20')

parseSpan('last 30 days')

parseSpan('this week')

scan('can we meet tomorrow at 5pm?')

Titles

Automatically extracts titles from expressions using common separators.

parse('Team offsite - March 10 to March 14')

parse('Sprint 1: jan 5 to jan 19')

parse('Meeting with Team (Jan 15 at 2pm)')

parse('Project Kickoff [March 1st]')

Options

parse('Q1', {

referenceDate: new Date('2025-06-01'),

fiscalYearStart: 'april',

weekStartsOn: 'monday',

dateFormat: 'intl'

})

Types

type ParseResult = DateResult | DurationResult | SpanResult | FuzzyResult | null

interface DateResult {

type: 'date'

date: Date

title: string | null

}

interface DurationResult {

type: 'duration'

duration: number

title: string | null

}

interface SpanResult {

type: 'span'

start: Date

end: Date

duration: number

title: string | null

}

interface FuzzyResult {

type: 'fuzzy'

start: Date

end: Date

approximate: true

title: string | null

}

interface ScanMatch {

result: ParseResult

match: string

start: number

end: number

}

Playground

Test each function individually.

parse()returns discriminated union

parseDate()returns Date | null

parseDuration()returns ms | null

parseSpan()returns { start, end, duration } | null

scan()returns array of matches with positions