Library / SDK
olebedev/when avatar
olebedev/when

olebedev/when: parsing natural language dates in Go

A natural language date/time parser with pluggable rules

1,465 stars96 forksGoApache-2.0

At a glance

What is it?
olebedev/when is a Go library for extracting dates and times from natural language text through pluggable rules. It suits applications that need best-effort parsing of English and four other supported languages, but its rule coverage and distance-based matching require explicit testing.
Who is it for?
Adopt olebedev/when when the input fits its documented rule grammar and relative dates can be resolved from a known reference time. Do not choose it as a general-purpose language understanding service or expect unlisted phrases to parse automatically.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What olebedev/when parses

olebedev/when addresses a narrow but practical problem in Go applications: turning phrases such as "tonight at 11:10 pm", "Friday afternoon", or "next tuesday 14:00" into a time value. The intended users are developers adding date extraction to messaging tools, scheduling interfaces, reminders, ticket systems, or other software that receives human-written dates. It is a library rather than a command-line program or service, so the caller supplies the text, registers rules, and supplies the reference time used to resolve relative expressions.

The supported rule sets are English, Russian, Brazilian Portuguese, Chinese, and Dutch. That list is important for adoption because the project does not present one universal natural language parser. Each language has its own rules, and the README directs users to the corresponding rule directory and tests for examples. A phrase that is understandable to a user is not necessarily covered merely because its meaning is obvious to a developer.

The parser is designed around matching a subset of an input string. Its result includes the parsed time, the matched text, and an index into the original string. The usage example prints both `r.Time.String()` and `text[r.Index:r.Index+len(r.Text)]`, which makes it possible to show which portion of the input produced the result. This is useful for interfaces that need to highlight or retain the original phrase, although the README does not document a CLI or a complete REST API. Those features appear in the TODO rather than as shipped interfaces.

Rule matching and context merging

The library first asks each registered rule whether it has a match in the supplied string. According to the README, a rule has borders based on the match length and its offset in the string, and each rule yields only its first match. The parser checks all rules and extracts a cluster whose matched rules are no farther apart than `options.Distance`, which defaults to 5.

After collecting the cluster, the library applies each matched rule to a context. Rules can be applied in definition order or match order, depending on `options.MatchByOrder`, which is enabled by default. Each rule can have a merge strategy. `Override` is the default strategy, and the README says other strategies are not implemented yet in the rules. This makes the architecture extensible at the rule level, but the current merge behavior is narrower than the terminology may initially suggest.

The distance setting is a real parsing constraint rather than a cosmetic option. In the README example, the date portion of "February 23, 2019 | 1:46pm" is nine characters away from the time portion. With the default distance of 5, the time is ignored. Increasing the distance to 10 allows both portions to participate, producing the correct date and afternoon time. A project that accepts punctuation, separators, or long descriptive text between a date and time may need to tune this value and test the consequences for nearby but unrelated matches.

Installing the Go module

The repository follows the official Go release workflow, and the README gives the module installation command below. The module path is `github.com/olebedev/when`, and the module file declares Go 1.19. The README says this installs the latest version. The command does not show a separate runtime configuration step, because `when` is imported as a Go package.

After installation, register the language rules you need and call `Parse` with the source text and the current time. The following is the first use shown in the README. It imports the English rules in the example context, adds `common.All`, and checks both an error and a nil result. An error means parsing failed according to the library API, while a nil result indicates that no matches were found.

A first Go parse with when.New

The following example is copied from the README's Usage section. The reader should see a parsed time for the phrase in `text`, followed by the matched substring `"next wednesday at 2:25 p.m"` when the parser finds that phrase. The exact printed time depends on `time.Now()` and on the rule implementation, so the important check is that the call returns a non-nil result without an error for this documented example.

go
w := when.New(nil)
w.Add(en.All...)
w.Add(common.All...)

text := "drop me a line in next wednesday at 2:25 p.m"
r, err := w.Parse(text, time.Now())
if err != nil {
	// an error has occurred
}
if r == nil {
	// no matches found
}

fmt.Println(
	"the time",
	r.Time.String(),
	"mentioned in",
	text[r.Index:r.Index+len(r.Text)],
)

The imports are not shown in the README excerpt, so they should be taken from the project example in the editor rather than invented as new APIs. The README also lists common rules separately from language rules. That separation allows an application to combine a language grammar with expressions that are not tied to one language.

Tuning distance for compound expressions

The distance example is the clearest warning against treating the parser as an unrestricted extractor. Start with the default configuration only when inputs resemble the README examples. For text containing a long separator, configure a larger distance and verify that the selected matches still form the intended semantic cluster.

go
w := when.New(nil)
w.Add(en.All...)
w.Add(common.All...)

text := "February 23, 2019 | 1:46pm"

w.SetOptions(&rules.Options{
	Distance:     10,
	MatchByOrder: true})

r, _ := w.Parse(text, time.Now())
fmt.Printf(r.Time.String())

The README states that `Distance: 10` allows the date and time to be considered together in this example. It does not claim that increasing the distance improves parsing for every input. A wider window can join more distant rule matches, including matches that a caller may consider unrelated. The option should therefore be set from representative application text, not just from one successful example. `MatchByOrder: true` retains the documented default behavior for deciding the order in which matched rules are applied.

Limits, language coverage, and alternatives

The main limitation is rule coverage. The README asks users to open an issue when a needed rule is missing, and its TODO includes implementing rules for additional examples. It also says the README does not yet describe all existing rules. This means an integration must inspect the language rule directory and tests rather than assume that common English expressions are covered. The library also lacks a CLI and simple REST API server, both listed as TODO items.

A different approach would be to send the input to a general natural language or date parsing service and accept a broader language model. That approach may recognize more varied phrasing, but it introduces a service dependency, different failure handling, and behavior outside the control of this Go module. `when` instead keeps rule definitions and matching in the application, with explicit control over supported languages, distance, and match order. The trade-off is that the application owns rule coverage and must test its own input domain.

The library is therefore a poor fit when free-form input must be interpreted without maintaining language-specific rules, or when a deployment requires an HTTP endpoint that the repository does not currently provide. It is a better fit when deterministic, pluggable rule behavior and local Go integration matter more than broad linguistic coverage. The repository is not archived, and its last push was on 2026-10-14. Its release history includes `v1.1.0`, published on 2024-11-12, but the README does not define a compatibility policy or upgrade procedure beyond following the official Go release workflow. The Apache-2.0 license permits use under its terms, but the license file and applicable obligations should be reviewed separately for a particular distribution.

Editorial conclusion

Adopt olebedev/when when the input fits its documented rule grammar and relative dates can be resolved from a known reference time. Do not choose it as a general-purpose language understanding service or expect unlisted phrases to parse automatically. Verify the required English or other-language rules, the effect of `options.Distance`, and the behavior of missing or conflicting matches before integrating it.

Frequently asked questions

How do I install olebedev/when in a Go project?

The README gives `go get github.com/olebedev/when@latest` as the installation command. The repository declares module path `github.com/olebedev/when` and Go 1.19 in `go.mod`.

Which languages does olebedev/when support?

The README lists English, Russian, Brazilian Portuguese, Chinese, and Dutch. Each language has a separate rules directory linked from the README.

Why is part of my olebedev/when date or time ignored?

The parser clusters matches only when their distance is less than or equal to `options.Distance`, which defaults to 5. The README shows that increasing the value can allow a date and time separated by a longer piece of text to be combined.

Does olebedev/when provide a CLI or REST API?

No. The README lists adding a CLI and a simple REST API server as TODO items, so the documented interface is the Go library API.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. olebedev/when on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/olebedev-when.svg)](https://hysenlabs.com/projects/olebedev-when)

Was this useful?