HTTP

Header

Date Header

Learn how the Date header specifies when the HTTP message was originated by the server. Understand date formats and its role in caching and logging.

7 min read beginner Try in Playground

TL;DR: Timestamp showing when the HTTP response was generated by the server. Required in all responses and used for cache freshness calculations and debugging.

What is Date?

The Date header contains the date and time at which the HTTP message was originated. It’s like a timestamp saying “This response was created at exactly this moment.”

This header is required in all HTTP responses and is used for caching calculations, age determination, and synchronization purposes.

How Date Works

Server sends response with Date:

HTTP/1.1 200 OK
Date: Sat, 18 Jan 2026 10:30:00 GMT
Content-Type: application/json
Cache-Control: max-age=3600

{"message": "Hello World"}
```text

The Date header tells the client when the response was generated, which helps with cache freshness calculations.

## Syntax

```http
Date: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT

Format

The Date header uses HTTP-date format (IMF-fixdate):

  • Day name: Mon, Tue, Wed, Thu, Fri, Sat, Sun
  • Month: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
  • Always in GMT/UTC timezone

Common Examples

Standard Response

Date: Sat, 18 Jan 2026 10:30:00 GMT
```http

Response generated on January 18, 2026 at 10:30 AM GMT.

### With Caching

```http
Date: Sat, 18 Jan 2026 10:30:00 GMT
Cache-Control: max-age=3600
Age: 300

Response is 5 minutes old (Age), expires 1 hour after Date.

API Response

Date: Sat, 18 Jan 2026 14:25:30 GMT
Content-Type: application/json
X-RateLimit-Reset: 1737207930
```text

Date header helps correlate with rate limit reset time.

## Real-World Scenarios

### Cache Freshness Calculation

```http
GET /api/data HTTP/1.1
Host: api.example.com

HTTP/1.1 200 OK
Date: Sat, 18 Jan 2026 10:00:00 GMT
Cache-Control: max-age=600
Age: 120

{"data": "cached content"}

# Freshness calculation:
# Response age: 120 seconds (Age header)
# Max age: 600 seconds (Cache-Control)
# Remaining fresh: 480 seconds (600 - 120)

Conditional Requests

# Initial request
GET /resource HTTP/1.1

HTTP/1.1 200 OK
Date: Sat, 18 Jan 2026 10:00:00 GMT
Last-Modified: Sat, 18 Jan 2026 09:00:00 GMT
ETag: "abc123"

# Subsequent request
GET /resource HTTP/1.1
If-Modified-Since: Sat, 18 Jan 2026 09:00:00 GMT

HTTP/1.1 304 Not Modified
Date: Sat, 18 Jan 2026 10:05:00 GMT
```http

### API Rate Limiting

```http
GET /api/endpoint HTTP/1.1

HTTP/1.1 200 OK
Date: Sat, 18 Jan 2026 12:00:00 GMT
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: Sat, 18 Jan 2026 13:00:00 GMT

Time-Sensitive Operations

POST /api/transactions HTTP/1.1

HTTP/1.1 201 Created
Date: Sat, 18 Jan 2026 15:30:45 GMT
Content-Type: application/json

{
  "id": "txn_123",
  "timestamp": "2026-01-18T15:30:45Z",
  "serverTime": "2026-01-18T15:30:45Z"
}
```javascript

## Server Implementation

### Express.js (Node.js)

```javascript
const express = require('express')
const app = express()

// Express automatically sets Date header, but you can set it manually
app.use((req, res, next) => {
  // Custom Date header (rarely needed)
  res.setHeader('Date', new Date().toUTCString())
  next()
})

app.get('/api/data', (req, res) => {
  // Date is automatically set
  res.json({ data: 'example' })
})

// Calculate response age
app.get('/cached', (req, res) => {
  const cacheDate = new Date('2026-01-18T10:00:00Z')
  const now = new Date()
  const age = Math.floor((now - cacheDate) / 1000)

  res.setHeader('Date', now.toUTCString())
  res.setHeader('Age', age.toString())
  res.setHeader('Cache-Control', 'max-age=3600')

  res.json({ cached: true })
})

// Check clock skew
app.use((req, res, next) => {
  const clientDate = req.headers.date
  if (clientDate) {
    const clientTime = new Date(clientDate).getTime()
    const serverTime = Date.now()
    const skew = Math.abs(serverTime - clientTime) / 1000

    if (skew > 300) {
      // 5 minutes
      console.warn(`Clock skew detected: ${skew} seconds`)
    }
  }
  next()
})

Custom Date Formatting

function formatHTTPDate(date) {
  const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
  const months = [
    'Jan',
    'Feb',
    'Mar',
    'Apr',
    'May',
    'Jun',
    'Jul',
    'Aug',
    'Sep',
    'Oct',
    'Nov',
    'Dec'
  ]

  const day = days[date.getUTCDay()]
  const dateNum = String(date.getUTCDate()).padStart(2, '0')
  const month = months[date.getUTCMonth()]
  const year = date.getUTCFullYear()
  const hour = String(date.getUTCHours()).padStart(2, '0')
  const minute = String(date.getUTCMinutes()).padStart(2, '0')
  const second = String(date.getUTCSeconds()).padStart(2, '0')

  return `${day}, ${dateNum} ${month} ${year} ${hour}:${minute}:${second} GMT`
}

app.use((req, res, next) => {
  res.setHeader('Date', formatHTTPDate(new Date()))
  next()
})
```javascript

### FastAPI (Python)

```python
from fastapi import FastAPI, Response
from datetime import datetime
from email.utils import formatdate
import time

app = FastAPI()

@app.middleware("http")
async def add_date_header(request, call_next):
    response = await call_next(request)

    # FastAPI sets Date automatically, but you can override
    response.headers["Date"] = formatdate(timeval=None, localtime=False, usegmt=True)

    return response

@app.get("/api/data")
async def get_data(response: Response):
    # Date is automatically set
    return {"data": "example"}

@app.get("/cached")
async def cached_response(response: Response):
    # Calculate age
    cache_time = datetime(2026, 1, 18, 10, 0, 0)
    now = datetime.utcnow()
    age = int((now - cache_time).total_seconds())

    response.headers["Date"] = formatdate(timeval=None, localtime=False, usegmt=True)
    response.headers["Age"] = str(age)
    response.headers["Cache-Control"] = "max-age=3600"

    return {"cached": True}

Django

from django.http import JsonResponse
from django.utils.http import http_date
import time

def api_view(request):
    # Django automatically sets Date header
    return JsonResponse({'data': 'example'})

def custom_date_view(request):
    response = JsonResponse({'data': 'example'})

    # Set custom Date (rarely needed)
    response['Date'] = http_date()

    return response

def cached_view(request):
    # Calculate age
    cache_timestamp = 1737198000  # Unix timestamp
    now = time.time()
    age = int(now - cache_timestamp)

    response = JsonResponse({'cached': True})
    response['Date'] = http_date()
    response['Age'] = str(age)
    response['Cache-Control'] = 'max-age=3600'

    return response
```nginx

### Nginx

```nginx
server {
    listen 80;
    server_name example.com;

    # Nginx automatically adds Date header

    location /api/ {
        # Date is always added by default
        proxy_pass http://backend;
    }

    # You can't easily override Date in Nginx
    # It's automatically set to the current time
}

Best Practices

For Servers

1. Always include Date header

# ✅ Required in all responses
HTTP/1.1 200 OK
Date: Sat, 18 Jan 2026 10:30:00 GMT

# ❌ Missing Date (violates HTTP spec)
HTTP/1.1 200 OK
Content-Type: text/html
```javascript

**2. Use correct GMT format**

```javascript
// ✅ Correct format
const date = new Date().toUTCString()
// "Sat, 18 Jan 2026 10:30:00 GMT"

// ❌ Wrong format
const date = new Date().toString()
// "Sat Jan 18 2026 10:30:00 GMT+0000"

3. Keep server clocks synchronized

# Use NTP to keep server time accurate
sudo timedatectl set-ntp true

# Check time synchronization
timedatectl status
```text

**4. Don't manipulate Date for caching tricks**

```http
# ❌ Bad: Faking the Date
Date: Sat, 18 Jan 2025 10:30:00 GMT  (when it's actually 2026)

# ✅ Good: Use proper caching headers
Date: Sat, 18 Jan 2026 10:30:00 GMT
Cache-Control: max-age=31536000

5. Include Age header for cached responses

# ✅ Clear cache status
Date: Sat, 18 Jan 2026 10:00:00 GMT
Age: 300
Cache-Control: max-age=3600
```javascript

### For Clients

**1. Use Date for cache calculations**

```javascript
async function fetchWithCacheCheck(url) {
  const response = await fetch(url)

  const date = new Date(response.headers.get('Date'))
  const age = parseInt(response.headers.get('Age') || '0')
  const maxAge = parseCacheControl(response.headers.get('Cache-Control'))

  const responseAge = age
  const freshnessLifetime = maxAge
  const isFresh = responseAge < freshnessLifetime

  console.log('Response date:', date)
  console.log('Is fresh:', isFresh)

  return response
}

2. Detect clock skew

fetch('/api/time').then((response) => {
  const serverDate = new Date(response.headers.get('Date'))
  const clientDate = new Date()
  const skew = Math.abs(serverDate - clientDate) / 1000

  if (skew > 60) {
    console.warn(`Clock skew detected: ${skew} seconds`)
  }
})
```javascript

**3. Use for retry-after calculations**

```javascript
fetch('/api/endpoint').then((response) => {
  if (response.status === 429) {
    const serverDate = new Date(response.headers.get('Date'))
    const retryAfter = parseInt(response.headers.get('Retry-After'))
    const retryTime = new Date(serverDate.getTime() + retryAfter * 1000)

    console.log('Retry after:', retryTime)
  }
})

Date Format Examples

HTTP-date Format (RFC 7231)

Date: Sat, 18 Jan 2026 10:30:00 GMT
```javascript

### JavaScript Generation

```javascript
// Correct HTTP date format
const httpDate = new Date().toUTCString()
// "Sat, 18 Jan 2026 10:30:00 GMT"

// ISO format (not for Date header)
const isoDate = new Date().toISOString()
// "2026-01-18T10:30:00.000Z"

Python Generation

from email.utils import formatdate

# Correct HTTP date format
http_date = formatdate(timeval=None, localtime=False, usegmt=True)
# "Sat, 18 Jan 2026 10:30:00 GMT"
```text

## Cache Freshness Calculation

### Formula

```text
response_age = Age header value OR (now - Date header value)
freshness_lifetime = max-age from Cache-Control
response_is_fresh = (response_age < freshness_lifetime)
```text

### Example

```http
Date: Sat, 18 Jan 2026 10:00:00 GMT
Cache-Control: max-age=600
Age: 120

# Current time: Sat, 18 Jan 2026 10:02:00 GMT
# Response age: 120 seconds (from Age header)
# Freshness lifetime: 600 seconds (from max-age)
# Fresh for: 480 more seconds (600 - 120)

Testing Date Header

Using curl

# Check Date header
curl -I https://example.com

# Verbose output to see Date
curl -v https://example.com

# Extract only Date header
curl -s -I https://example.com | grep -i "^Date:"
```javascript

### Using JavaScript

```javascript
// Check server date
fetch('https://api.example.com').then((response) => {
  const dateHeader = response.headers.get('Date')
  const serverTime = new Date(dateHeader)
  const clientTime = new Date()

  console.log('Server time:', serverTime)
  console.log('Client time:', clientTime)
  console.log('Difference:', Math.abs(serverTime - clientTime) / 1000, 'seconds')
})

// Calculate cache freshness
fetch('https://api.example.com/cached').then((response) => {
  const date = new Date(response.headers.get('Date'))
  const age = parseInt(response.headers.get('Age') || '0')
  const cacheControl = response.headers.get('Cache-Control')
  const maxAgeMatch = cacheControl.match(/max-age=(\d+)/)
  const maxAge = maxAgeMatch ? parseInt(maxAgeMatch[1]) : 0

  console.log('Response age:', age, 'seconds')
  console.log('Max age:', maxAge, 'seconds')
  console.log('Fresh for:', maxAge - age, 'seconds')
})

Frequently Asked Questions

What is the Date header?

Date indicates when the message was generated. Servers should include it in all responses. It uses HTTP-date format in GMT timezone.

What format does Date use?

HTTP-date format: Date: Wed, 21 Oct 2026 07:28:00 GMT. Always use GMT timezone. The format is defined in RFC 9110.

Is Date required?

Servers with a clock should include Date in responses. It is important for caching calculations and debugging. Clients rarely send Date.

How is Date used in caching?

Caches use Date with Age header to calculate response freshness. Date shows when the origin generated the response, Age shows time in cache.

Keep Learning