Date Handling in Elasticsearch
Introduction
Elasticsearch supports the date type as a type for storing and querying using dates and times. Dates can be stored and used for querying in the following flavors.
an ISO date such as
2008-04-21
, without a time component.an ISO date-time such as
2008-04-21T10:32:45
which includes a time component.
When data is imported into Elasticsearch from java, you can send a LocalDate
object or a LocalDateTime
object, depending on whether your data includes a time component or is just date only.
Listing a Mapping
You can view the mapping of an index to verify whether a particular field is stored as a date
. To do that, use the following request.
curl -X GET "localhost:9200/orders.csv/_mapping"
Which results in the following output. Note that Order Date
is stored as a date.
"orders.csv": {
"mappings": {
"doc": {
"properties": {
"Customer ID": {
"type": "long"
},
"Employee ID": {
"type": "long"
},
"Notes": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"Order Date": {
"type": "date"
},
...
Querying by date
A sample set of hits from the index listed above is shown below. As you can see, the field Order Date
contains a date-time in ISO format. (For this example, the time is 00:00:00
; that is how the original data was presented.)
"hits": [
{
"_index": "orders.csv",
"_type": "doc",
"_id": "1",
"_score": 1.0,
"_source": {
"Order ID": 30,
"Employee ID": 9,
"Customer ID": 27,
"Order Date": "2006-01-15T00:00:00.000",
"Shipped Date": "2006-01-22T00:00:00.000",
"Shipper ID": 2,
"Ship Name": "Karen Toh",
"Ship Address": "789 27th Street",
"Ship City": "Las Vegas",
"Ship State/Province": "NV",
"Ship ZIP/Postal Code": 99999,
"Ship Country/Region": "USA",
"Shipping Fee": "$200.00",
"Taxes": "$0.00",
"Payment Type": "Check",
"Paid Date": "2006-01-15T00:00:00.000",
"Notes": "",
"Tax Rate": 0.0,
"Tax Status": "",
"Status ID": 3
}
},
...
The following query is used for fetching hits that restrict the date to on or before 2006-01-15
(using the lte operator). Note that we specify just the date in the form 1/16/2006
and a suitable format to go with it.
{
"query": {
"bool": {
"must": [
{
"range": {
"Order Date": {
"format": "M/d/yyyy",
"lte": "1/15/2006"
}
}
}
]
}
},
"from": 0,
"size": 25
}
The results are shown partially below.
"hits": [
{
"_index": "joe.csv",
"_type": "doc",
"_id": "1",
"_score": 1.0,
"_source": {
"Order ID": 30,
"Employee ID": 9,
"Customer ID": 27,
"Order Date": "2006-01-15T00:00:00.000",
"Shipped Date": "2006-01-22T00:00:00.000",
"Shipper ID": 2,
"Ship Name": "Karen Toh",
"Ship Address": "789 27th Street",
"Ship City": "Las Vegas",
"Ship State/Province": "NV",
"Ship ZIP/Postal Code": 99999,
"Ship Country/Region": "USA",
"Shipping Fee": "$200.00",
"Taxes": "$0.00",
"Payment Type": "Check",
"Paid Date": "2006-01-15T00:00:00.000",
"Notes": "",
"Tax Rate": 0.0,
"Tax Status": "",
"Status ID": 3
}
}
...
Date Format directives
You can specify the date format by setting the format
property to a combination of the codes shown below.
Code | Meaning | Examples |
---|---|---|
G | era | AD; Anno Domini; A |
u | year | 2004; 04 |
y | year-of-era | 2004; 04 |
D | day-of-year | 189 |
M | month-of-year | 7; 07; Jul; July; J |
L | month-of-year | 7; 07; Jul; July; J |
d | day-of-month | 10 |
Q/q | quarter-of-year | 3; 03; Q3; 3rd quarter |
Y | week-based-year | 1996; 96 |
w | week-of-week-based-year | 27 |
W | week-of-month | 4 |
E | day-of-week | Tue; Tuesday; T |
e/c | localized day-of-week | 2; 02; Tue; Tuesday; T |
F | week-of-month | 3 |
a | am-pm-of-day | PM |
h | clock-hour-of-am-pm (1-12) | 12 |
K | hour-of-am-pm (0-11) | 0 |
k | clock-hour-of-am-pm (1-24) | 0 |
H | hour-of-day (0-23) | 0 |
m | minute-of-hour | 30 |
s | second-of-minute | 55 |
S | fraction-of-second | 978 |
A | milli-of-day | 1234 |
n | nano-of-second | 987654321 |
N | nano-of-day | 1234000000 |
V | time-zone ID | America/Los_Angeles; Z; -08:30 |
z | time-zone name | Pacific Standard Time; PST |
O | localized zone-offset | GMT+8; GMT+08:00; UTC-08:00; |
X | zone-offset ‘Z’ for zero | Z; -08; -0830; -08:30; -083015; -08:30:15; |
x | zone-offset | +0000; -08; -0830; -08:30; -083015; -08:30:15; |
Z | zone-offset | +0000; -0800; -08:00; |
p | pad next | 1 |
’ | escape for text | ‘arbitrary text here’ |
’’ | single quote | ‘we have here a’’ (single quote)’ |
[ | optional section start | |
] | optional section end |
Importing data containing dates
Argon automatically identifies data types when importing data in most cases. This is done by parsing the first 100 rows to identify the data types as one of: integer, float, boolean and date.
In the image below, two fields birth_date
and hire_date
have been identified as dates without a time component.
The following shows importing a file with dates including a time component.
Querying date fields in Argon
1. Invoke the Filter-by-Date dialog by choosing Select Date Range from the context menu.
2. The Filter-by-Date dialog is shown.
Select the date to filter by, and the condition from among <
, <=
, >
or >=
. Since the date field does not include time, the time field is grayed out. Click Apply to run the query.
3. The query JSON is shown below.
The selected date and the format are specified as shown.
{
"from": 0,
"query": {
"bool": {
"must": [
{
"range": {
"birth_date": {
"lt": "1960-1-11",
"format": "yyyy-M-d"
}
}
}
]
}
},
"size": 25
}
And a snapshot of the results:
"hits": [
{
"_index": "employees.csv",
"_type": "doc",
"_id": "70001",
"_score": 1.0,
"_source": {
"emp_no": 80001,
"birth_date": "1956-09-30",
"first_name": "Nagui",
"last_name": "Merli",
"gender": null,
"hire_date": "1986-06-12"
}
},
{
"_index": "employees.csv",
"_type": "doc",
"_id": "70005",
"_score": 1.0,
"_source": {
"emp_no": 80005,
"birth_date": "1957-04-01",
"first_name": "Sanjit",
"last_name": "Nyrup",
"gender": null,
"hire_date": "1989-02-12"
}
},
...
Searching for a specific date
To run a query restricting a field to a particular date, specify both <=
and >=
with the same date.
The query JSON is shown below.
{
"size": 25,
"query": {
"bool": {
"must": [
{
"range": {
"birth_date": {
"lte": "1962-9-5",
"gte": "1962-9-5",
"format": "yyyy-M-d"
}
}
}
]
}
},
"from": 0
}
And the result hits:
"hits": [
{
"_index": "employees.csv",
"_type": "doc",
"_id": "70010",
"_score": 1.0,
"_source": {
"emp_no": 80010,
"birth_date": "1962-09-05",
"first_name": "Olivera",
"last_name": "Munke",
"gender": null,
"hire_date": "1990-03-24"
}
},
{
"_index": "employees.csv",
"_type": "doc",
"_id": "73885",
"_score": 1.0,
"_source": {
"emp_no": 83885,
"birth_date": "1962-09-05",
"first_name": "Raimond",
"last_name": "Merks",
"gender": false,
"hire_date": "1989-08-13"
}
},
...
Search for a specific date and time
With a DateTime field, you can query for a specific date and time. When the field supports time, the time field will be active and you can enter the time.
The query is shown below. Note that the specified time is included, along with the format the date is specified in.
{
"size": 25,
"query": {
"bool": {
"must": [
{
"range": {
"Measurement Timestamp": {
"lte": "5/28/2014 1:0:0 PM",
"format": "M/d/yyyy' 'h:m:s a"
}
}
}
]
}
},
"from": 0
}
And you can see the results below.
Date and time range
Here is an example which shows a date-time range query.
The query JSON is shown below. Date and time are included in the query along with a suitable format.
{
"query": {
"bool": {
"must": [
{
"range": {
"Measurement Timestamp": {
"format": "M/d/yyyy' 'h:m:s a",
"lte": "5/28/2014 2:0:0 PM",
"gte": "5/28/2014 1:0:0 PM"
}
}
}
]
}
},
"from": 0,
"size": 25
}
A sampling of the hits:
"hits": [
{
"_index": "beach_water_quality_-_automated_sensors.csv",
"_type": "doc",
"_id": "6",
"_score": 1.0,
"_source": {
"Beach Name": "Montrose Beach",
"Measurement Timestamp": "2014-05-28T13:00:00.000",
"Water Temperature": 14.5,
"Turbidity": 2.72,
"Transducer Depth": 1.395,
"Wave Height": 0.306,
"Wave Period": 3,
"Battery Life": 11.9,
"Measurement Timestamp Label": "2014-05-28T13:00:00.000",
"Measurement ID": "MontroseBeach201405281300"
}
},
{
"_index": "beach_water_quality_-_automated_sensors.csv",
"_type": "doc",
"_id": "7",
"_score": 1.0,
"_source": {
"Beach Name": "Calumet Beach",
"Measurement Timestamp": "2014-05-28T13:00:00.000",
"Water Temperature": 16.3,
"Turbidity": 1.28,
"Transducer Depth": 1.524,
"Wave Height": 0.162,
"Wave Period": 4,
"Battery Life": 11.7,
"Measurement Timestamp Label": "2014-05-28T13:00:00.000",
"Measurement ID": "CalumetBeach201405281300"
}
},
Summary
While Elasticsearch supports storage and querying date and time, it is easiest to use an application like Argon to help with the data import. Also, composing dates and times in a suitable format is all handled in a intuitive way for you.