Parsing dates and time in Java
Published: 2024-04-29 02:23:39

The other day I needed to parse some timestamp strings loaded from a file. It's for a test where I wanted to feed these timestamps as `Instant` to an object I'm trying test. These time strings are like `2023-12-05 17:51:00-08:00`. 

First thing I tried was to just parse it:

```java
Instant time = Instant.parse(timeString);
```

Of course it throws, right? Looked like I had to roll up my sleeves and figure out the right `DateTimeFormatter` before being able to parse them.

I kinda remembered that for the date, it's `yyyy-MM-dd` (important to use the upper case `MM`); and for the time it's `hh-mm-ss`. But I had no idea how to specify the timezone offset part.

So I went to read the javadoc of `DateTimeFormatter`. In retrospect, if I were in the mood of learning the API for the purpose of learning, it must have been fine. But I was more like:

> C'mon, I just need to parse some timestamp. Where is the quick example that matches the format?

Unfortunately the javadoc reads more like a RFC document, with no cheetsheet that could help me in a hurry.

After deciding to sit down, and take my time to learn it, I finally figured out. And by the way I was wrong, it's not `hh-mm-ss` but `HH-mm-ss`. Oh well.

End of story.

But I hated this kind of yak shaving. You need to put aside the immediate task you had in mind, and instead research the knowledge for a preliminary step. 

A colleague told me that what I want is something [Golang does](https://go.dev/src/time/format.go). That is, they don't use cryptic format specifiers, but instead just use an example datetime string.

I was like "shut up and take my money!" because it's exactly what I need: I don't have the specifiers, but I do have an example date time string.

Learning a bit more though, Golang's use of the magical reference date gave me the pause: if I can't remember the format specifiers, can I remember the magic date? It turns out that reference time isn't really intuitive either:

```
01/02 03:04:05PM 06 -0700
```

That stikes me as a bit too cute:
  * What year is `01/02`?
  * Why PM? While it looks like natural `1-2-3-4-5-6-7`, in the time format I'm most familiar with, it'll actually be `15:04:05`, not easy to remember at all.
  * Why `-0700` but not `+07:00`?

And if it only takes the reference date, I can't just pass a random string to parse without myself having to translate it to the reference date with my own man power.

The burning question is: _if I can read `2023-12-05 17:51:00-08:00` and understand exactly what time it is, no ambiguity, and without knowing a reference time or the format specifiers, why can't the computer?_ This is no rocket science or AlphaGo.

So I started to build [a library](https://github.com/google/mug/wiki/Parsing-Date-Time-Should-Be-10x-Easier) to help me parse all common dates and time strings. It should be able to infer from the input what the format specifiers should be (supports timezone, weekday, even including formats like `11/30/2024`), and then use that format specifier to parse the date or time for me:

```java
// Directly parsing dates and time
Instant timestamp = DateTimeFormats.parseToInstant(
   "2023-12-05 17:51:00-08:00");
LocalDate date = DateTimeFormats.parseLocalDate(
   "2023-12-05");
ZonedDateTime zonedDateTime = DateTimeFormats.parseZonedDateTime(
   "2023-12-05 17:51:00-08:00");

// Infer the DateTimeFormatter
DateTimeFormatter format = DateTimeFormats.formatOf(
   "2023-12-05 17:51:00-08:00");
```

It was a fun little project to build. Using the [Substring](https://github.com/google/mug/wiki/Substring-Explained) library as the basic building block, I mostly avoided having to use regex or fiddling with string indexes and off-by-1 errors. 

I like that it allows me to use any example date and time, without having to remember anything at all.

Maybe it'll be useful to you too?