Akka HTTP & java.time: ISO‑8601 Date Header Parsing Compatibility
28K reputation · 28 May 2026, 06:13 UTC
Integration Boundary: Akka HTTP & java.time
The goal is to ensure that HTTP requests containing an ISO‑8601 formatted Date header are correctly interpreted by an Akka HTTP service that otherwise relies on java.time for time‑zone handling. Akka HTTP’s current HttpDate parser accepts only RFC1123, RFC1036, and ANSI C asctime formats, omitting ISO‑8601 and explicit time‑zone offsets. This mismatch forces application code to perform manual parsing or to reject otherwise valid requests.
Constraints include maintaining backward compatibility with existing Akka HTTP releases, avoiding invasive changes to the core HTTP layer, and preserving the lightweight nature of the framework. The uncertainty lies in whether Akka HTTP should expose ISO‑8601 parsing directly or delegate entirely to java.time in a future release.
Key questions for the community:
- Should Akka HTTP add native ISO‑8601 parsing to its
HttpDateimplementation, and if so, how should time‑zone offsets be handled? - What is the recommended pattern for integrating
java.timeparsing in the request pipeline without duplicating logic across services? - Is there a design trade‑off between extending Akka HTTP’s parser and maintaining a clear separation between HTTP protocol handling and application‑level date logic?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
28,025 reputation · 28 May 2026, 08:56 UTC
Why ISO‑8601 isn’t in the core parser
Akka HTTP’s built‑in DateHeader follows RFC 7231 and only accepts the IMF‑fixdate (RFC1123) format. An ISO‑8601 string like 2023‑10‑05T12:34:56Z will be rejected during request parsing.
Using a custom Header extractor
Define a header extractor that delegates to java.time.Instant (or OffsetDateTime if you need the offset) and register it via HeaderDirectives.
import akka.http.scaladsl.model.headers.{Header, HeaderName}
import java.time.Instant
object IsoDateHeader extends Header[Instant] {
val name = HeaderName("Date")
def parse(value: String): Try[Instant] = Try(Instant.parse(value))
def renderIn(b: Builder): Unit = b.add(name, value.toString)
}
// In a route
extractHeader(IsoDateHeader) { instant =>
// use instant (UTC) in your logic
}
For responses, format the Instant with DateTimeFormatter.ISO_INSTANT and set it via the same header extractor, keeping the header value ISO‑8601 while the framework still treats it as a Header[Instant]. This approach preserves backward compatibility and keeps protocol handling separate from application logic.