Index

Time in REST APIs

Java Date and Time

19.1 Designing APIs with ISO-8601 Support

When designing REST APIs, representing dates and times consistently and unambiguously is crucial for interoperability and correctness. The ISO-8601 standard is the widely accepted format for exchanging date and time information in APIs due to its clear structure and timezone-awareness.

Why ISO-8601?

Benefits of Using ISO-8601 in APIs

Examples of ISO-8601 in API Payloads

Request example: Submitting an event with a date and timestamp

POST /api/events
{
  "eventName": "Product Launch",
  "startDate": "2025-11-15",                       // ISO Local Date
  "startTime": "2025-11-15T09:00:00Z",             // ISO Instant (UTC)
  "registrationDeadline": "2025-11-10T23:59:59-05:00"  // ISO Offset Date-Time with timezone offset
}

Response example: Returning event details

GET /api/events/123
{
  "eventId": 123,
  "eventName": "Product Launch",
  "startDate": "2025-11-15",
  "startTime": "2025-11-15T09:00:00Z",
  "registrationDeadline": "2025-11-10T23:59:59-05:00",
  "createdAt": "2025-06-22T14:30:45.123Z"          // ISO Instant with milliseconds precision
}

Documenting ISO-8601 Formats in API Specs

Clear documentation helps clients understand exactly how to send and interpret date/time values:

Example OpenAPI snippet:

components:
  schemas:
    Event:
      type: object
      properties:
        startDate:
          type: string
          format: date
          description: "Event start date in ISO-8601 date format (yyyy-MM-dd)"
          example: "2025-11-15"
        startTime:
          type: string
          format: date-time
          description: "Event start time in ISO-8601 date-time format with UTC or offset"
          example: "2025-11-15T09:00:00Z"

Summary

Designing REST APIs with ISO-8601 date/time support ensures:

By adopting ISO-8601 as the de facto standard in your API design and documenting it thoroughly, you create a solid foundation for working with time data in modern distributed applications.

Index

19.2 Validating and Parsing Input Dates

In REST APIs, validating and parsing incoming date and time strings is essential to ensure data integrity and avoid runtime errors. This section explains robust strategies to handle date/time inputs, including how to parse ISO-8601 formats and custom patterns with Java's DateTimeFormatter. It also covers error handling and fallback strategies to build resilient endpoints.

Parsing Dates with DateTimeFormatter

Java’s DateTimeFormatter provides a flexible and powerful way to parse date/time strings. It supports both the standard ISO-8601 formats and custom patterns.

Example: Parsing ISO-8601 Date-Time

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class DateParser {

    private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ISO_DATE_TIME;

    public static LocalDateTime parseIsoDateTime(String input) throws IllegalArgumentException {
        try {
            return LocalDateTime.parse(input, ISO_FORMATTER);
        } catch (DateTimeParseException ex) {
            throw new IllegalArgumentException("Invalid ISO-8601 date-time format: " + input, ex);
        }
    }
}

Example: Parsing a Custom Date Format

Suppose your API expects dates in "dd/MM/yyyy HH:mm:ss" format:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class CustomDateParser {

    private static final DateTimeFormatter CUSTOM_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");

    public static LocalDateTime parseCustomDateTime(String input) throws IllegalArgumentException {
        try {
            return LocalDateTime.parse(input, CUSTOM_FORMATTER);
        } catch (DateTimeParseException ex) {
            throw new IllegalArgumentException("Invalid date-time format, expected dd/MM/yyyy HH:mm:ss: " + input, ex);
        }
    }
}

Validating Incoming Input in REST Endpoints

In a typical Spring Boot REST controller, you can validate date input strings by catching exceptions during parsing and returning meaningful error responses.

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/events")
public class EventController {

    @PostMapping("/schedule")
    public ResponseEntity<String> scheduleEvent(@RequestParam String startTime) {
        try {
            LocalDateTime parsedDate = DateParser.parseIsoDateTime(startTime);
            // Proceed with valid date
            return ResponseEntity.ok("Event scheduled for: " + parsedDate);
        } catch (IllegalArgumentException ex) {
            return ResponseEntity.badRequest().body(ex.getMessage());
        }
    }
}

Handling Missing or Invalid Dates

public LocalDateTime parseOrDefault(String input, LocalDateTime defaultValue) {
    if (input == null || input.isBlank()) {
        return defaultValue;
    }
    try {
        return LocalDateTime.parse(input, DateTimeFormatter.ISO_DATE_TIME);
    } catch (DateTimeParseException e) {
        return defaultValue;
    }
}

Summary of Best Practices

By rigorously validating and parsing date/time inputs using DateTimeFormatter, you build robust REST APIs that handle temporal data consistently and predictably, improving client experience and server reliability.

Index

19.3 Dealing with Time Zones in APIs

Handling time zones correctly in REST APIs is crucial to avoid confusion, data inconsistency, and bugs — especially in distributed systems where clients and servers may operate across multiple regions. This section discusses common pitfalls with time zones, design principles for time zone–aware APIs, and best practices for both clients and servers.

Common Pitfalls with Time Zones in APIs

Design Principles for Time ZoneAware APIs

Examples of Handling Time Zones in Java APIs

Storing UTC Instant:

import java.time.Instant;

Instant utcNow = Instant.now(); // UTC timestamp
System.out.println(utcNow);  // e.g., 2025-06-22T19:00:00Z

Parsing and Returning ZonedDateTime with Offset:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

String input = "2025-06-22T15:00:00-04:00";  // Eastern Daylight Time (EDT)
ZonedDateTime zdt = ZonedDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);

System.out.println(zdt);  // preserves offset

Converting ZonedDateTime to UTC Instant for Storage:

Instant instant = zdt.toInstant();
System.out.println(instant);  // normalized to UTC
Click to view full runnable Code

import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class TimeZoneHandlingExample {
    public static void main(String[] args) {
        // Storing UTC Instant
        Instant utcNow = Instant.now(); // UTC timestamp
        System.out.println("Current UTC Instant: " + utcNow);

        // Parsing and returning ZonedDateTime with offset
        String input = "2025-06-22T15:00:00-04:00";  // Eastern Daylight Time (EDT)
        ZonedDateTime zdt = ZonedDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        System.out.println("Parsed ZonedDateTime: " + zdt);

        // Converting ZonedDateTime to UTC Instant for storage
        Instant instant = zdt.toInstant();
        System.out.println("Converted to UTC Instant: " + instant);
    }
}

Best Practices for Clients and Servers

Reflection

Time zones add complexity to temporal data handling, but thoughtful API design — centered on explicitness, normalization to UTC, and proper conversion — greatly reduces bugs and misunderstandings. Ensuring both clients and servers respect these principles leads to reliable, user-friendly applications across global environments.

By adopting these best practices, you create REST APIs that correctly handle time zones, enabling consistent, unambiguous time communication throughout your distributed systems.

Index