The Problem

Did you ever have any of these errors?

  • missing Location in call to Time.In
  • missing Location in call to Date
panic: time: missing Location in call to Time.In

goroutine 1 [running]:
time.Time.In(...)
        /usr/local/go/src/time/time.go:1146
main.main()
        /app/main.go:16 +0x1c5

Does your code look somewhat like this?

location, _ := time.LoadLocation("Europe/Amsterdam")

name, offset := time.Now().In(location).Zone()

log.Println("name: "+name, "offset: "+strconv.Itoa(offset))

Are you using Alpine or a similar distribution in your Docker container?

Are you using a multistep Dockerfile build process?

Alpine does not contain timezone data inside the distribution. This means, the time.LoadLocation returns a nil for loading the location, leading to the panic at time.Now().In.

The Solution

At first, I suggest changing the code in a way that the error is getting caught.

location, err := time.LoadLocation("Europe/Amsterdam")
if err != nil {
    log.Fatal(err)
}

Next, there are at least two solutions. Either add the timezone info into the distribution or use a base image that has timezone info.

1. Add timezone info

The solution is to add the timezone info in your Docker build step. But let’s clarify first why this helps.

The Go runtime checks a couple of locations for timezone information. You can read more about the exact behaviour in the Golang LoadLocation documentation . Essentially, there are 4 locations that are checked in order:

  • the directory or uncompressed zip file named by the ZONEINFO environment variable
  • on a Unix system, the system standard installation location
  • $GOROOT/lib/time/zoneinfo.zip
  • the time/tzdata package, if it was imported

We can see that the Go distribution contains timezone info, we can copy that and reference it via an environment variable.

The following code assumes that the first step in your Docker file is called builder. Please change the base step name accordingly.

Add these lines to your Dockerfile:

# Copy timezone from Golang base image
COPY --from=builder /usr/local/go/lib/time/zoneinfo.zip /

# Specify timezone info location for Go application
ENV ZONEINFO=/zoneinfo.zip

Your Dockerfile might look like this in the end:

# Build stage
FROM golang:1.22 as builder

# Install musl-dev and gcc for Alpine compatibility
RUN apt-get update && apt-get install -y musl-dev musl-tools gcc

# Set the Current Working Directory inside the container
WORKDIR /app

# Copy go.mod and go.sum files
COPY go.mod go.sum ./

# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download

# Copy the source code into the container
COPY . .

# Build the Go app
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o application .

## Final stage
FROM alpine:latest as final

## Install necessary packages, e.g. ca-certificates, if your application needs it
RUN apk --no-cache add ca-certificates

WORKDIR /app

## Copy the pre-built binary file from the previous stage
COPY --from=builder /app/application /app/application
COPY --from=builder /usr/local/go/lib/time/zoneinfo.zip /
ENV ZONEINFO=/zoneinfo.zip

CMD ["/app/application"]

2. Use different base image

In case the timezone info does not work for you, you might want try using a different base image like Ubuntu. Keep in mind that this will result in larger final image sizes.

Further Reading