How to set the correct timezone for a Rust application in a scratch docker environment?

I have a Dockerfile which builds a Rust application and puts it in a scratch image.

# build application

FROM ubuntu:latest as system-deps
RUN apt-get update && apt-get install -y tzdata

FROM scratch
COPY --from=system-deps /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=app-builder --chown=myuser:myuser /app/ryot /app
ENTRYPOINT ["/app"]

However, regardless of what timezone I specify using the --env TZ="<a valid timezone>" docker flag, I always get the current UTC.

How can I make it respect the timezone?

Here is an article I found pertaining to Go projects: Using local time in a Golang Docker container built from Scratch | by Chris Binder | Medium
Entire dockerfile: https://github.com/IgnisDa/ryot/blob/ec3194eee6840f4eed902d7fa1a78a6824d8f878/Dockerfile#L45

This question is not specific to Rust. Add a /etc/localtime symlink via the Dockerfile. See localtime(5) - Linux manual page

But that makes me have to hardcore the value at docker build time. I want the users to be able to set the TZ environment variable.

Use a build argument.

That would still force users to build their own docker images. That is not how configuration works. Eg: GitHub - bonukai/MediaTracker: Self hosted media tracker for movies, tv shows, video games, books and audiobooks

Ok, do it the hard way.

You aren’t really supposed to change the environment in Rust, but you can if you isolate it. It just ends up being code that is completely unnecessary.

How would I do that?

As I said in my original post, I am already settings the environment variable.

My question is why is Rust not respecting it?

Wht does it mean by Rust not respecting it? Are you using crates like time or chrono?

Yes I am using chrono.

The chrono crate uses types like Local and Utc to set the timezone, where Local comes from the system (i.e. /etc/localtime). For example, chrono::DateTime<Utc> will give you UTC times.

If you want it dynamically configured via a $TZ environment variable then create your own TimeZone implementation that does what you want. To the best of my knowledge, there is no built-in thing that uses a $TZ environment variable for setting the timezone, so it's not surprising that --env TZ=... does nothing.

But doesn't chrono use TZ?

1 Like

I think the issue is that the scratch layer doesn't contain the timezone database, so it fails to load the timezone file for the TZ you specified causing a fallback to UTC. https://github.com/chronotope/chrono/blob/38b19bbe4e21c402f81edfa2932a43831e679a35/src/offset/local/tz_info/timezone.rs#L614 Chrono looks in /usr/share/zoneinfo, /share/zoneinfo, /etc/zoneinfo and /usr/share/lib/zoneinfo in that order. Try copying the timezone database from your host system or download it from Time Zone Database

3 Likes

Build FROM gcr.io/distroless/base instead of FROM scratch. That will include the time zone database and libc.