Dalc: an online date calculator written in Rust

posted on 2023-10-19

There are plenty of date calculators on the web, but if they don't push adds in your face constantly, they push cookie warnings. And on top of that, because this is an ancient issue, they have you send your date on a roundtrip to what feels like an old PHP server in a dusty closet. So I decided to write my own: instant client-side results using Rust.

Introduction

This all started when I joined a project that was using a timestamp as a sort key on a DynamoDB table in AWS. The timestamp was actually a date truncated timestamp in UTC, so every time I wanted to know the date I would have to run a utility method or go on the internet and dodge ads.

I heard about Leptos on the The Rustacean Station Podcast and decided that was the way to go. And so Dalc began.

Using Leptos

It was the first time I used Leptos, so it took some time to wrap my head around.

One thing that worked out well was the date parsing with Chrono, here I could just take the input String and try different parsers to see what would stick:

let parsers = [
|ival: &str| {
            DateTime::parse_from_rfc3339(ival)
                .map(|x| x.with_timezone(&Utc))
                .ok()
        },
        |ival: &str| {
            DateTime::parse_from_rfc2822(ival)
                .map(|x| x.with_timezone(&Utc))
                .ok()
        },
        // the list goes on
]
parsers.iter().filter_map(|f| f(&input_value)).next()

This results in an Option<DateTime<Utc>>.

Then for the Leptos part. First create a Signal that allows you to propagate changes to the HTML and hook that into an text input on-change:

let (datetime_a, set_datetime_a) = create_signal(cx, None);
view! { cx,
    <input type="text" placeholder="Date time, 2020-01-01"
        on:input=move |ev| {
            set_datetime_a(parse_input(event_target_value(&ev).trim().to_string()));
        }
    />
}

Then we can pass the ReadSignal<Option<DateTime<Utc>>> into another component that will render the result:

view! { cx,
    "ISO 8601 / RFC 3339: " {move || datetime_a.get().map(|nd| nd.to_rfc3339()).unwrap_or(String::from("?"))}
}

The code is not pretty, but it works and certainly fixed an itch I had.

You can find the source code at https://github.com/bneijt/dalc and the live website at https://bneijt.nl/pr/dalc/

Happy hacking!