DEV Community

delay.run
delay.run

Posted on

'Remind me next Tuesday at 3': 6 libraries for parsing natural-language dates, and the traps in each

If your product schedules anything, sooner or later someone asks for a text box where people can just type "tomorrow at 9am" or "in 2 hours" or "next Tuesday at 3". It's a great experience when it works. It's a confusing one when it doesn't, because a wrong guess looks exactly like a right one until the reminder fires on the wrong day.

Here are six libraries that turn human-written dates into real timestamps, grouped by language, with the traps worth testing for each. Libraries change, so check each project's current documentation and maintenance status before you adopt one.

The traps they all share

Before the list, the problems every parser has to deal with. Test any library against these:

  • "Next Friday." On a Wednesday, is that in two days or nine? People genuinely disagree.
  • Day/month order. "03/04" is March 4 in some countries and April 3 in others.
  • Time zones. "9am" in whose zone? The server's, the user's browser, or the user's saved setting?
  • Times in the past. "At 9am", typed at 10am. Today, which has passed, or tomorrow?
  • Ambiguous words. "This weekend", "end of the month", "tonight".
  • Daylight saving. "In 24 hours" and "tomorrow at the same time" differ on clock-change days.

The library is only half the solution. The other half is showing the user what you understood.

1. Chrono (JavaScript / TypeScript)

What it is: A popular natural-language date parser for JavaScript, usable in Node and the browser.

Good for: Extracting dates from free text: "Let's meet next Tuesday at 3pm" gives you the date and the position of the matched text. It supports a reference date, so "tomorrow" is calculated relative to the moment you choose, and has options for preferring future dates.

Watch out for: Language support varies by locale, with English the most complete. Make sure you pass the user's time zone and reference time explicitly rather than relying on the server's.

import * as chrono from "chrono-node";
// Pass the reference moment explicitly; check the docs for how your
// version accepts the user's time zone in the reference object.
const ref = { instant: new Date() };
const result = chrono.parseDate("next Tuesday at 3pm", ref, { forwardDate: true });
Enter fullscreen mode Exit fullscreen mode

2. dateparser (Python)

What it is: A Python library that parses dates in many languages and formats, including relative expressions like "2 hours ago" or "in 3 days".

Good for: Multilingual input and messy formats, for example from scraped pages or user messages. It has settings for preferring future or past dates, choosing date order and setting the time zone.

Watch out for: It's flexible, which means it will confidently parse things you might want to reject. Configure PREFER_DATES_FROM, DATE_ORDER and the time zone settings deliberately, and test with your users' real phrases.

import dateparser
dateparser.parse("next tuesday 3pm", settings={
    "PREFER_DATES_FROM": "future",
    "TIMEZONE": "Europe/Lisbon",
    "RETURN_AS_TIMEZONE_AWARE": True,
})
Enter fullscreen mode Exit fullscreen mode

3. parsedatetime (Python)

What it is: An older, smaller Python library focused on English natural-language dates and times.

Good for: Simple English phrases where you want something lightweight.

Watch out for: It returns a time structure plus a status flag telling you whether it parsed a date, a time, both or neither. Check that flag; otherwise "banana" quietly becomes "now".

4. Duckling (Haskell, run as a service)

What it is: A parser originally from Facebook that extracts structured data, including dates, times, durations and intervals, from text in many languages. It's typically run as an HTTP service.

Good for: Chat interfaces and voice assistants, where you need dates, durations ("for 2 hours") and intervals ("from 3 to 5") in many languages, from any programming language.

Watch out for: It's a separate service to deploy and maintain, and the repository's activity has varied over time. Check its current state before depending on it.

5. Chronic (Ruby)

What it is: A long-standing natural-language date parser for Ruby.

Good for: Ruby apps that need English phrases like "tomorrow", "3 months from now" or "last day of the month".

Watch out for: Time zone handling depends on how you configure it with your app's time settings. Test with your app's real time zone configuration, not just the defaults.

6. Natty (Java)

What it is: A natural-language date parser for Java.

Good for: JVM applications that need English relative dates and date ranges.

Watch out for: The project hasn't seen much recent activity, so treat it as stable but not actively evolving, and check compatibility with your Java version.

The pattern that matters more than the library

Whichever parser you choose, the most important step is the same: show the user what you understood before saving it.

You typed: "next tuesday at 3"
We'll remind you: Tuesday 10 November, 15:00 (Lisbon time)   [Change]
Enter fullscreen mode Exit fullscreen mode

That one line catches nearly every ambiguity on the list above. The user sees the actual date and time zone, and corrects it if it's wrong, before anything is scheduled.

A few more habits:

  • Store the parsed result in UTC, plus the user's time zone, not the original text.
  • Keep the original text too, for debugging and support.
  • Reject or question low-confidence results instead of guessing.
  • Write tests from real user input. Collect the phrases people actually type; they're stranger than you'd expect.

Turning "next Tuesday at 3" into a job that runs at exactly the right moment is the kind of problem we think about at delay.run.

Related reading

What's the most ambiguous date phrase a user has typed into your product, and what did your code decide it meant?

Top comments (0)