1. HTTP (Hypertext Transfer Protocol)

  1. HTTP Headers

  1. Date
    1. Requests
    2. Writing Responses
      1. strftime
    3. Reading Responses
      1. Estimating Server Time using the Date header
    4. Overview table
    5. Syntax
      1. Example
    6. Implementations
      1. Node.js
      2. PHP

Date

Specifies date the message was generated. If the message is a file off a database or filesystem, it specifies when the file was read (Last-Modified specifies the time the file was modified). If the message is served from a cache from a previous HTTP request, it specifies the time the upstream message was initially generated (and Age specifies how long has passed since then).

Requests

The Date header is optional in requests, and generally not necessary. It may be employed in specialized applications when the server would benefit from knowing the Client's time, for example if clock drift is important to the application.

Writing Responses

A server must include the Date header in responses, unless an reasonable approximation of the current date is not known.

A layer forwarding a message must add the Date header if it does not exist, and has a reasonable approximation.

The date can be any moment during the generation of the request, but ideally represents the moment the payload was generated, and when headers are written to the client.

The date must be in the IMF-fixdate format, described below.

strftime

This strftime template produces an HTTP compatible date, compatible with C strftime/strptime, and similar implementations:

%a, %d %b %Y %H:%M:%S %Z

The locale must be set to GMT when formatting this template. If the return value ends in anything except the 4-character string GMT, then the value is invalid, and locale is not configured properly.

Reading Responses

Other dates in the HTTP headers should be interpreted relative to this date, if present, instead of using the local machine's clock.

Although servers are only supposed to produce the "IMF-fixdate" format, older servers might produce two other formats, described with the obs-date production (below).

Estimating Server Time using the Date header

Clients may use HTTP headers to obtain the current time according to the server; which may be used when reading other timestamps provided by the server; even if the local client clock is drifting or very wrong.

To estimate the server time, take the value of the Date header and add the value of the Age header in seconds, if it exists:

const messageAge = Number.parseInt(response.getHeader('Age') || 0, 10);
const messageDate = Date.parse(response.getHeader('Date'));
assert(messageDate > 0);
const serverDate = new Date(messageDate + messageAge*1000);

The produced value should always be accurate plus or minus a second, plus or minus the duration of the request.

Overview table

Name
Date
Description
Specifies the date that the origin server generated the response.
Direction
Both
Specification
RFC 7231: HTTP/1.1 Semantics and Content ยง7.1.1.2. Date

Syntax

Date = HTTP-date
HTTP-date = IMF-fixdate / obs-date
IMF-fixdate  = day-name "," SP date1 SP time-of-day SP GMT

; fixed length/zone/capitalization subset of the format
; see Section 3.3 of [RFC5322]

day-name     = %x4D.6F.6E ; "Mon", case-sensitive
             / %x54.75.65 ; "Tue", case-sensitive
             / %x57.65.64 ; "Wed", case-sensitive
             / %x54.68.75 ; "Thu", case-sensitive
             / %x46.72.69 ; "Fri", case-sensitive
             / %x53.61.74 ; "Sat", case-sensitive
             / %x53.75.6E ; "Sun", case-sensitive

date1        = day SP month SP year
; e.g., 02 Jun 1982

day          = 2DIGIT
month        = %x4A.61.6E ; "Jan", case-sensitive
             / %x46.65.62 ; "Feb", case-sensitive
             / %x4D.61.72 ; "Mar", case-sensitive
             / %x41.70.72 ; "Apr", case-sensitive
             / %x4D.61.79 ; "May", case-sensitive
             / %x4A.75.6E ; "Jun", case-sensitive
             / %x4A.75.6C ; "Jul", case-sensitive
             / %x41.75.67 ; "Aug", case-sensitive
             / %x53.65.70 ; "Sep", case-sensitive
             / %x4F.63.74 ; "Oct", case-sensitive
             / %x4E.6F.76 ; "Nov", case-sensitive
             / %x44.65.63 ; "Dec", case-sensitive
year         = 4DIGIT

GMT          = %x47.4D.54 ; "GMT", case-sensitive

time-of-day  = hour ":" minute ":" second
				 ; 00:00:00 - 23:59:60 (leap second)

hour         = 2DIGIT
minute       = 2DIGIT
second       = 2DIGIT

Obsolete formats:

obs-date     = rfc850-date / asctime-date
rfc850-date  = day-name-l "," SP date2 SP time-of-day SP GMT
date2        = day "-" month "-" 2DIGIT
             ; e.g., 02-Jun-82
day-name-l   = %x4D.6F.6E.64.61.79    ; "Monday", case-sensitive
             / %x54.75.65.73.64.61.79       ; "Tuesday", case-sensitive
             / %x57.65.64.6E.65.73.64.61.79 ; "Wednesday", case-sensitive
             / %x54.68.75.72.73.64.61.79    ; "Thursday", case-sensitive
             / %x46.72.69.64.61.79          ; "Friday", case-sensitive
             / %x53.61.74.75.72.64.61.79    ; "Saturday", case-sensitive
             / %x53.75.6E.64.61.79          ; "Sunday", case-sensitive
asctime-date = day-name SP date3 SP time-of-day SP year
date3        = month SP ( 2DIGIT / ( SP 1DIGIT ))
             ; e.g., Jun  2

Example

Date: Tue, 15 Nov 1994 08:12:31 GMT

Implementations

Node.js

V8's implementation of Date#toUTCString function produces an IMF-fixdate compatible string.

All three versions can be parsed by V8's new Date(string), so test that the header matches one of the legal input formats, then pass the entire string to a new Date instance.

// String#match will return an array with:
// [full, day_name, day, month_name, year, hour, minute, second]
var IMF_fixdate = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/;

// [full, day_name, day, month_name, year, hour, minute, second]
var rfc850_date = /^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{2}) (\d\d):(\d\d):(\d\d) GMT$/;

// [full, day_name, month_name, day, hour, minute, second, year]
var asctime_date = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([ 0-9][0-9]) (\d\d):(\d\d):(\d\d) (\d{4})$/;

function parseHTTPDate(str){
	if(typeof str !== 'string') throw new Error('Expected a string');
	if(IMF_fixdate.test(str) || rfc850_date.test(str) || asctime_date.test(str)) return new Date(str);
	throw new Error('Invalid HTTP-date');
}

PHP

All known HTTP servers that run PHP, including as PHP's builtin testing server, will produce a Date header in response by default.

If the Date header needs to be written or parsed despite this, use the DATE_RFC7231 or DateTimeInterface::RFC7231 constants available since since PHP 7.1.5:

$Date = gmdate(DATE_RFC7231);
$Date = (new DateTimeImmutable())->format(DateTimeInterface::RFC7231);

The strtotime function or DateTimeImmutable class can parse a Date header:

$unixtime = strtotime("Tue, 15 Nov 1994 08:12:31 GMT");
$datetime = new DateTimeImmutable("Tue, 15 Nov 1994 08:12:31 GMT");