Python Datemath
What?
A date math (aka datemath) parser compatiable with the elasticsearch "date math" format
What is "date math"?
Date Math is the short hand arithmetic to find relative time to fixed moments in date and time. Similar to the SOLR date math format, we aim to support that same coverage in python.
The date type supports using date math expression when using it in a query/filter (mainly makes sense in range query/filter).
The expression starts with an "anchor" date, which can be either now or a date string (in the applicable format) ending with ||
.
It can then follow by a math expression, supporting +
, -
and /
(rounding).
The units supported are y
(year), M
(month), w
(week), d
(day), h
(hour), m
(minute), and s
(second).
Here are some samples: now+1h
, now+1h+1m
, now+1h/d
, 2012-01-01||+1M/d
.
Note, when doing range type searches, and the upper value is inclusive, the rounding will properly be rounded to the ceiling instead of flooring it.
Unit Maps
The "unit maps" here define the shorthand sytax for the dates/timeframes we are working with:
y or Y = 'year'
M = 'month'
m = 'minute'
d or D = 'day'
w = 'week'
h or H = 'hour'
s or S = 'second'
now = <current_time_and_date>
Examples
Here are some examples of using date math to find dates both in the past and in the future
Assuming our "now" datetime is currently: 2016-01-01T00:00:00-00:00
Expression: Result:
now-1h 2015-12-31T23:00:00+00:00
now-1y 2015-01-01T00:00:00+00:00
now+1y+2d 2017-01-03T00:00:00+00:00
now+12h 2016-01-01T12:00:00+00:00
now+1d/d 2016-01-03T00:00:00+00:00
now-2.5h 2015-12-31T21:30:00+00:00
+2h 2016-01-01T02:00:00+00:00
+1h/h 2016-01-01T02:00:00+00:00
now+1w/w 2016-01-11T00:00:00+00:00
now/d+7d+12h 2016-01-08T12:00:00+00:00
2016-01-01||+1d 2016-01-02T00:00:00+00:00
2015-01-01||+2w 2015-01-15T00:00:00+00:00
now/d 2016-01-01T23:59:59+00:00
now/Y 2016-12-31T23:59:59+00:00
Usage
If you use the dm
function in the datemath module, we will return an arrow date object representing your timestamp.
>>> from datemath import dm
>>>
>>> dm('now+1h')
<Arrow [2016-01-01T01:00:00+00:00]>
>>> dm('now+1h+1m')
<Arrow [2016-01-01T01:01:00+00:00]>
>>> dm('now+1h/d')
<Arrow [2016-01-02T00:00:00+00:00]>
>>> dm('now-1d')
<Arrow [2015-12-31T00:00:00+00:00]>
>>> dm('2016-01-01||+1/d')
<Arrow [2016-01-02T00:00:00+00:00]>
>>> dm('now/d+2h+3m')
<Arrow [2016-01-01T02:03:00+00:00]>
>>> dm('now+/d', roundDown=False)
<Arrow [2016-01-01T23:59:00+00:00]>
>>> dm('now/d')
<Arrow [2016-01-01T00:00:00+00:00]>
>>> dm(1451610061)
<Arrow [2016-01-01T01:01:01+00:00]>
>>> dm('1451610061')
<Arrow [2016-01-01T01:01:01+00:00]>
If you would rather have a string, you can use arrow's .format()
method.
For for info on string formatting, check out arrows tokens section: http://crsmithdev.com/arrow/#tokens
>>> from datemath import dm
>>>
>>> src_timestamp = dm('2016-01-01')
>>> print src_timestamp
2016-01-01T00:00:00+00:00
>>>
>>> new_timestamp = dm('-2w', now=src_timestamp)
>>> print new_timestamp
2015-12-18T00:00:00+00:00
>>>
>>> new_timestamp.format('YYYY.MM.DD')
u'2015.12.18'
If you would rather have your time object come back in standard python datetime
, use the datemath
function instead:
>>> from datemath import datemath
>>>
>>> datemath("now-1h")
datetime.datetime(2015, 12, 31, 23, 0, tzinfo=tzutc())
>>> str(datemath("now-1h"))
'2015-12-31 23:00:00+00:00'
>>>
>>> datemath('2016-01-01T16:20:00||/d')
datetime.datetime(2016, 1, 1, 0, 0, tzinfo=tzutc())
>>>
>>> datemath('2016-01-01T16:20:00||/d', roundDown=False)
datetime.datetime(2016, 1, 1, 23, 59, 59, 999999, tzinfo=tzutc())
Or you can use the dm
function and set its type
to datetime
:
from datemath import dm
>>> dm('now', type='datetime')
datetime.datetime(2016, 1, 22, 22, 58, 28, 338060, tzinfo=tzutc())
>>>
>>> dm('now+2d-1m', type='datetime')
datetime.datetime(2016, 1, 24, 22, 57, 45, 394470, tzinfo=tzutc())
If you want a Epoch timestamp back instead, we can do that too.
>>> dm('now+2d-1m', type='timestamp')
1453676321
What timezone are my objects in?
By default all objects returned by datemath are in UTC.
If you want them them back in a different timezone, just pass along the tz
argument. Timezone list can be found here: https://gist.github.com/pamelafox/986163
If you provide a timezone offset in your timestring, datemath will return your time object as that timezone offset in the string.
Note - currently timestrings with a timezone offset and the usage of the tz
argument will result in the time object being returned with the timezone of what was in the timezone offset in the original string
>>> from datemath import dm
>>>
>>> dm('now')
<Arrow [2016-01-26T01:00:53.601088+00:00]>
>>>
>>> dm('now', tz='US/Eastern')
<Arrow [2016-01-25T20:01:05.976880-05:00]>
>>>
>>> dm('now', tz='US/Pacific')
<Arrow [2016-01-25T17:01:18.456882-08:00]>
>>>
>>> dm('2017-10-20 09:15:20', tz='US/Pacific')
<Arrow [2017-10-20T09:15:20.000000-08:00]>
>>>
>>>
>>> dm('2016-01-01T00:00:00-05:00')
<Arrow [2016-01-01T00:00:00-05:00]>
>>>
>>>
>>> dm('2016-01-01T00:00:00-05:00||+2d+3h+5m')
<Arrow [2016-01-03T03:05:00-05:00]>
>>>
>>>
>>> dm('2016-01-01T00:00:00-05:00', tz='US/Central')
<Arrow [2016-01-01T00:00:00-05:00]>
Install
pip install python-datemath
Debugging
If you would like more verbose output to debug the process of what datemath is doing, simply set export DATEMATH_DEBUG=true
in your shell then run some datemath tests. To stop debugging, run unset DATEMATH_DEBUG
.
Changes
See CHANGELOG.md
Happy date math'ing!