[[date]]
=== Date field type
++++
<titleabbrev>Date</titleabbrev>
++++

JSON doesn't have a date data type, so dates in Elasticsearch can either be:

* strings containing formatted dates, e.g. `"2015-01-01"` or `"2015/01/01 12:10:30"`.
* a number representing _milliseconds-since-the-epoch_.
* a number representing _seconds-since-the-epoch_ (<<date-epoch-seconds, configuration>>).

NOTE: Values for _milliseconds-since-the-epoch_ must be non-negative. Use a
formatted date to represent dates before 1970.

Internally, dates are converted to UTC (if the time-zone is specified) and
stored as a long number representing milliseconds-since-the-epoch.

Queries on dates are internally converted to range queries on this long
representation, and the result of aggregations and stored fields is converted
back to a string depending on the date format that is associated with the field.

NOTE: Dates will always be rendered as strings, even if they were initially
supplied as a long in the JSON document.

Date formats can be customised, but if no `format` is specified then it uses
the default:

[source,js]
----
    "strict_date_optional_time||epoch_millis"
----
// NOTCONSOLE

This means that it will accept dates with optional timestamps, which conform
to the formats supported by <<strict-date-time,`strict_date_optional_time`>>
or milliseconds-since-the-epoch.

For instance:

[source,console,id=date-example]
--------------------------------------------------
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "date": {
        "type": "date" <1>
      }
    }
  }
}

PUT my-index-000001/_doc/1
{ "date": "2015-01-01" } <2>

PUT my-index-000001/_doc/2
{ "date": "2015-01-01T12:10:30Z" } <3>

PUT my-index-000001/_doc/3
{ "date": 1420070400001 } <4>

GET my-index-000001/_search
{
  "sort": { "date": "asc"} <5>
}
--------------------------------------------------

<1> The `date` field uses the default `format`.
<2> This document uses a plain date.
<3> This document includes a time.
<4> This document uses milliseconds-since-the-epoch.
<5> Note that the `sort` values that are returned are all in milliseconds-since-the-epoch.

[WARNING]
====
Dates
// tag::decimal-warning[]
will accept numbers with a decimal point like `{"date": 1618249875.123456}`
but there are some cases ({es-issue}70085[#70085]) where we'll lose precision
on those dates so should avoid them.
// end::decimal-warning[]
====

[[multiple-date-formats]]
==== Multiple date formats

Multiple formats can be specified by separating them with `||` as a separator.
Each format will be tried in turn until a matching format is found. The first
format will be used to convert the _milliseconds-since-the-epoch_ value back
into a string.

[source,console,id=date-format-example]
--------------------------------------------------
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "date": {
        "type":   "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}
--------------------------------------------------

[[date-params]]
==== Parameters for `date` fields

The following parameters are accepted by `date` fields:

[horizontal]

<<mapping-boost,`boost`>>::

    Mapping field-level query time boosting. Accepts a floating point number, defaults
    to `1.0`.

<<doc-values,`doc_values`>>::

    Should the field be stored on disk in a column-stride fashion, so that it
    can later be used for sorting, aggregations, or scripting? Accepts `true`
    (default) or `false`.

<<mapping-date-format,`format`>>::

    The date format(s) that can be parsed. Defaults to
    `strict_date_optional_time||epoch_millis`.

`locale`::

    The locale to use when parsing dates since months do not have the same names
    and/or abbreviations in all languages. The default is the
    https://docs.oracle.com/javase/8/docs/api/java/util/Locale.html#ROOT[`ROOT` locale],

<<ignore-malformed,`ignore_malformed`>>::

    If `true`, malformed numbers are ignored. If `false` (default), malformed
    numbers throw an exception and reject the whole document.  Note that this
    cannot be set if the `script` parameter is used.

<<mapping-index,`index`>>::

    Should the field be searchable? Accepts `true` (default) and `false`.

<<null-value,`null_value`>>::

    Accepts a date value in one of the configured +format+'s as the field
    which is substituted for any explicit `null` values. Defaults to `null`,
    which means the field is treated as missing.  Note that this cannot be
    set of the `script` parameter is used.


`on_script_error`::

    Defines what to do if the script defined by the `script` parameter
    throws an error at indexing time. Accepts `fail` (default), which
    will cause the entire document to be rejected, and `continue`, which
    will register the field in the document's
    <<mapping-ignored-field,`_ignored`>> metadata field and continue
    indexing. This parameter can only be set if the `script` field is
    also set.

`script`::

    If this parameter is set, then the field will index values generated
    by this script, rather than reading the values directly from the
    source. If a value is set for this field on the input document, then
    the document will be rejected with an error.
    Scripts are in the same format as their
    <<runtime-mapping-fields,runtime equivalent>>, and should emit
    long-valued timestamps.

<<mapping-store,`store`>>::

    Whether the field value should be stored and retrievable separately from
    the <<mapping-source-field,`_source`>> field. Accepts `true` or `false`
    (default).

<<mapping-field-meta,`meta`>>::

    Metadata about the field.


[[date-epoch-seconds]]
==== Epoch seconds

If you need to send dates as _seconds-since-the-epoch_ then make sure the
`format` lists `epoch_second`:

[source,console,id=date-epoch-seconds-example]
----
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "date": {
        "type":   "date",
        "format": "strict_date_optional_time||epoch_second"
      }
    }
  }
}

PUT my-index-000001/_doc/example?refresh
{ "date": 1618321898 }

POST my-index-000001/_search
{
  "fields": [ {"field": "date"}],
  "_source": false
}
----
// TEST[s/_search/_search?filter_path=hits.hits/]

Which will reply with a date like:

[source,console-result]
----
{
  "hits": {
    "hits": [
      {
        "_id": "example",
        "_index": "my-index-000001",
        "_type": "_doc",
        "_score": 1.0,
        "fields": {
          "date": ["2021-04-13T13:51:38.000Z"]
        }
      }
    ]
  }
}
----
