Module datetime
Since: 2.10.0
The datetime module provides support for the
datetime and interval data types.
You can create date and time values either via the object interface or
by parsing string values conforming to the ISO-8601 standard.
Below is a list of datetime functions, properties, and related
objects.
Functions
- datetime.new() — create an object of the
datetimetype from a table of time units - datetime.now() — create an object of the
datetimetype with the current date and time - datetime.is_datetime() — check whether the
specified value is a
datetimeobject - datetime.parse() — convert an input string with the
date and time information into a
datetimeobject - datetime.interval.is_interval() —
check whether the specified value is an
intervalobject - datetime.interval.new() — create an object of
the
intervaltype from a table of time units
Properties
- datetime.TZ — a Lua table that maps timezone names and abbreviations to their index and vice versa.
Methods
- datetime_object:add() — modify an existing
datetimeobject by adding values of the input argument - datetime_object:format() — convert the standard
datetimeobject presentation into a formatted string - datetime_object:set() — update the field values in the
existing
datetimeobject - datetime_object:sub() — modify an existing
datetimeobject by subtracting values of the input argument - datetime_object:totable() — convert the
information from a
datetimeobject into the table format - interval_object:totable() — convert the
information from an
intervalobject into the table format
Create an object of the datetime type from a table of time units. See the description of units and examples below.
Parameters:
units(table) — Table of time units. If an empty table or no arguments are passed, thedatetimeobject with the default values corresponding to the Unix Epoch is created:1970-01-01T00:00:00Z.
Returns
Return type
cdata
Name | Description | Type | Default |
|---|---|---|---|
nsec (usec, msec) | Fractional part of the last second. You can specify either nanoseconds
( | number | 0 |
sec | Seconds. Value range: 0 - 60. A leap second is supported at the most basic level, see the section leap second. | number | 0 |
min | Minutes. Value range: 0 - 59. | number | 0 |
hour | Hours. Value range: 0 - 23. | number | 0 |
day | Day number. Value range: 1 - 31. The special value | number | 1 |
month | Month number. Value range: 1 - 12. | number | 1 |
year | Year. | number | 1970 |
timestamp | Timestamp, in seconds. Similar to the Unix timestamp, but can have a
fractional part that is converted into nanoseconds in the resulting
| number | 0 |
tzoffset | A time zone offset from UTC, in minutes. Value range: -720 to 840
inclusive. If both | number | 0 |
tz | A time zone name according to the Time Zone Database. See the timezone section. | string |
tarantool> datetime.new {> nsec = 123456789,>> sec = 20,> min = 25,> hour = 18,>> day = 20,> month = 8,> year = 2021,>> tzoffset = 180> }---- 2021-08-20T18:25:20.123456789+0300...tarantool> datetime.new {> nsec = 123456789,> sec = 20,> min = 25,> hour = 18,> day = 20,> month = 8,> year = 2021,> tzoffset = 60,> tz = 'Europe/Moscow'> }---- 2021-08-20T18:25:20.123456789 Europe/Moscow...tarantool> datetime.new {> day = -1, month = 2, year = 2021,> }---- 2021-02-28T00:00:00Z...tarantool> datetime.new {> timestamp = 1656664205.123, tz = 'Europe/Moscow'> }---- 2022-07-01T08:30:05.122999906 Europe/Moscow...tarantool> datetime.new {> nsec = 123, timestamp = 1656664205, tz = 'Europe/Moscow'> }---- 2022-07-01T08:30:05.000000123 Europe/Moscow...
Create an object of the datetime type with the current date and time.
Returns
Return type
cdata
Check whether the specified value is a datetime object.
Parameters:
value(any) — the value to check
Returns
true if the specified value is a datetime object; otherwise,
false
Return type
boolean
Convert an input string with the date and time information into a
datetime object. The input string must be formatted according to one
of the following standards:
By default, fields that are not specified are equal to the appropriate values of the Unix time.
Leap seconds are supported at the most basic level, see the section leap second.
Parameters:
input_string(string) — string with the date and time information.format(string) — indicator of theinput_stringformat. Possible values: 'iso8601', 'rfc3339', or astrptime-like format string. If no value is set, the default formatting is used ("%F %T %Z"). Note that only a part of possible ISO 8601 and RFC 3339 formats is supported. To parse unsupported formats, you can specify a format string manually using conversion specifications and ordinary characters.tzoffset(number) — time zone offset from UTC, in minutes.
Returns
a datetime object
Return type
cdata
Returns
the number of parsed characters
Return type
number
Implementation details:
-
For formats with a decimal fraction of the second ([1], 5.3.1.4, a), the tail beyond 9 fractional digits is truncated.
tarantool> datetime.parse('2024-07-31T17:30:00.123456789999', {format = 'iso8601'})---- 2024-07-31T17:30:00.123456789Z- 32... -
For formats with a decimal fraction of the hour ([1], 5.3.1.4, c) or minute ([1], 5.3.1.4, b), the fractions are truncated to seconds precision. If second fractions are needed, the explicit representation (format a) must be used.
tarantool> datetime.parse('2024-07-31T17,333333333', {format = 'iso8601'})---- 2024-07-31T17:19:59Z- 23...tarantool> datetime.parse('2024-07-31T17:30.333333333', {format = 'iso8601'})---- 2024-07-31T17:30:19Z- 26...
Example:
tarantool> datetime.parse('1970-01-01T00:00:00Z')---- 1970-01-01T00:00:00Z- 20...tarantool> t = datetime.parse('1970-01-01T00:00:00', {format => 'iso8601', tzoffset = 180})---tarantool> t---- 1970-01-01T00:00:00+0300...tarantool> t = datetime.parse('2017-12-27T18:45:32.999999-05:00',> {format = 'rfc3339'})---tarantool> t---- 2017-12-27T18:45:32.999999-0500...tarantool> T = datetime.parse('Thu Jan 1 03:00:00 1970', {format => '%c'})---tarantool> T---- 1970-01-01T03:00:00Z...tarantool> T = datetime.parse('12/31/2020', {format = '%m/%d/%y'})---tarantool> T---- 2020-12-31T00:00:00Z...tarantool> T = datetime.parse('1970-01-01T03:00:00.125000000+0300',> {format = '%FT%T.%f%z'})---tarantool> T---- 1970-01-01T03:00:00.125+0300...tarantool> dt = datetime.parse('01:01:01 MSK', {format ='%H:%M:%S %Z'})---tarantool> dt.year---- 1970...tarantool> dt.month---- 1...tarantool> dt.wday---- 5...tarantool> dt.tz---- MSK...
Since: 3.2.0
Check whether the specified value is an interval object.
Parameters:
value(any) — the value to check
Returns
true if the specified value is an interval object; otherwise,
false
Return type
boolean
Examples:
If a numeric value is passed to is_interval(), false is returned:
tarantool> datetime = require('datetime')---tarantool> datetime.interval.is_interval(123)---- false...
If an interval object is passed to is_interval(), true is returned:
tarantool> datetime.interval.is_interval(datetime.interval.new())---- true...
Create an object of the interval type from a table of time units. See the description of units, and the examples below.
Parameters:
input(table) — Table with time units and parameters. For all possible time units, values are unrestricted. If an empty table or no arguments are passed, theintervalobject with the default value of0 secondsis created.
Returns
interval_object
Return type
cdata
Name | Description | Type | Default |
|---|---|---|---|
nsec (usec, msec) | Fractional part of the last second. You can specify either nanoseconds
( | number | 0 |
sec | Seconds | number | 0 |
min | Minutes | number | 0 |
hour | Hours | number | 0 |
day | Days | number | 0 |
week | Weeks | number | 0 |
month | Months | number | 0 |
year | Year | number | 0 |
adjust | Defines how to round days in a month after an arithmetic operation. | string | 'none' |
tarantool> datetime.interval.new()---- 0 seconds...tarantool> datetime.interval.new {> month = 6, year = 1> }---- +1 years, 6 months...tarantool> datetime.interval.new {> day = -1> }---- `-1 days`...
Since: 2.11.0
A Lua table that maps timezone names (for example, Europe/Moscow) and
timezone abbreviations (for example, MSK) to their index and vice
versa. See the timezone section.
tarantool> datetime.TZ['Europe/Moscow']---- 947...tarantool> datetime.TZ[947]---- Europe/Moscow...
A datetime object.
Modify an existing datetime object by adding values of the input
argument. See also: interval_arithm. The addition is
performed taking tzdata into account, if tzoffset or tz fields are
set (see timezone).
Parameters:
input(table) — an interval object or an equivalent table (see Example #1)adjust(string) — defines how to round days in a month after an arithmetic operation. Possible values:none,last,excess(see Example #2). Defaults tonone.
Returns
datetime_object
Return type
cdata
Example #1:
tarantool> dt = datetime.new {> day = 26,> month = 8,> year = 2021,> tzoffset = 180> }---tarantool> iv = datetime.interval.new {day = 7}---tarantool> dt, iv---- 2021-08-26T00:00:00+0300- +7 daystarantool> dt:add(iv)---- 2021-09-02T00:00:00+0300tarantool> dt:add{ day = 7 }---- 2021-09-09T00:00:00+0300
tarantool> dt = datetime.new {> day = 29,> month = 2,> year = 2020> }---tarantool> dt:add{month = 1, adjust = 'none'}---- 2020-03-29T00:00:00Ztarantool> dt = datetime.new {> day = 29, month = 2, year = 2020> }---tarantool> dt:add{month = 1, adjust = 'last'}---- 2020-03-31T00:00:00Ztarantool> dt = datetime.new {> day = 31, month = 1, year = 2020> }---tarantool> dt:add{month = 1, adjust = 'excess'}---- 2020-03-02T00:00:00Z
Convert the standard datetime object presentation into a formatted
string. The conversion specifications are the same as in the
strftime
function. An additional specification for nanoseconds is %f, which
also allows using a modifier to control the output precision of the
fractional part: %5f (see the example below). If no arguments are set
for the method, the default conversions are used: '%FT%T.%f%z' (see
the example below).
Parameters:
input_string(string) — a string consisting of zero or more conversion specifications and ordinary characters
Returns
a string with the formatted date and time information
Return type
string
Example:
tarantool> dt = datetime.new {> nsec = 123456789,>> sec = 20,> min = 25,> hour = 18,>> day = 20,> month = 8,> year = 2021,>> tzoffset = 180> }---tarantool> dt:format('%d.%m.%y %H:%M:%S.%5f')---- 20.08.21 18:25:20.12345tarantool> dt:format()---- 2021-08-20T18:25:20.123456789+0300tarantool> dt:format('%FT%T.%f%z')---- 2021-08-20T18:25:20.123456789+0300
Update the field values in the existing datetime object.
Parameters:
units(table) — a table of time units. The time units are the same as for thedatetime.new()function.
Returns
updated datetime_object
Return type
cdata
Example:
tarantool> dt = datetime.new {> nsec = 123456789,>> sec = 20,> min = 25,> hour = 18,>> day = 20,> month = 8,> year = 2021,>> tzoffset = 180> }---tarantool> dt:set {msec = 567}---- 2021-08-20T18:25:20.567+0300tarantool> dt:set {tzoffset = 60}---- 2021-08-20T18:25:20.567+0100
Modify an existing datetime object by subtracting values of the input
argument. See also: interval_arithm. The subtraction is
performed taking tzdata into account, if tzoffset or tz fields are
set (see timezone).
Parameters:
input(table) — an interval object or an equivalent table (see Example)adjust(string) — defines how to round days in a month after an arithmetic operation. Possible values:none,last,excess. Defaults tonone. The logic is similar to the one of the:add()method – see Example #2.
Returns
datetime_object
Return type
cdata
Example:
tarantool> dt = datetime.new {> day = 26,> month = 8,> year = 2021,> tzoffset = 180> }---tarantool> iv = datetime.interval.new {day = 5}---tarantool> dt, iv---- 2021-08-26T00:00:00+0300- +5 daystarantool> dt:sub(iv)---- 2021-08-21T00:00:00+0300tarantool> dt:sub{ day = 1 }---- 2021-08-20T00:00:00+0300
Convert the information from a datetime object into the table format.
The resulting table has the following fields:
Field name | Description |
|---|---|
nsec | Nanoseconds. Number. |
sec | Seconds. Number. |
min | Minutes. Number. |
hour | Hours. Number. |
day | Day number. |
month | Month number. |
year | Year. Number. |
wday | Days since the beginning of the week. Number. 1 is Sunday, as for
|
yday | Days since the beginning of the year. Number. |
timestamp | Timestamp, in seconds. Number. |
isdst | Whether the DST (Daylight Saving Time) is applicable for the date, see the timezone section. Boolean. |
tzoffset | Time zone offset from UTC, see the timezone section. Number. |
tz | Time zone name or abbreviation, see the timezone section. String. |
Returns
a table with date and time parameters
Return type
table
Example:
tarantool> dt = datetime.new {> sec = 20,> min = 25,> hour = 18,>> day = 20,> month = 8,> year = 2021,> tz = 'MAGT',> }---tarantool> dt:totable()---- tz: 'MAGT'sec: 20 min: 25 yday: 232 day: 20 nsec: 0 isdst: false wday: 6tzoffset: 600 month: 8 year: 2021 hour: 18
An interval object.
Convert the data from an interval object into the table format. The
resulting table has the following fields:
Field name | Description |
|---|---|
nsec | Nanoseconds |
sec | Seconds |
min | Minutes |
hour | Hours |
day | Day number |
month | Month number |
year | Year |
week | Week number |
adjust | Defines how to round days in a month after an arithmetic operation. |
Returns
a table with date and time parameters
Return type
table
Example:
tarantool> iv = datetime.interval.new{month = 1, adjust = 'last'}---tarantool> iv:totable()---- adjust: lastsec: 0 nsec: 0 day: 0 week: 0 hour: 0 month: 1 year: 0 min: 0
The datetime module allows creating objects of two types: datetime
and interval.
If you need to shift the values of a datetime object, you can use the
modifier methods, that is, datetime_object:add() or
datetime_object:sub(), or apply interval arithmetic
using the overloaded + (__add) or - (__sub) operators.
The datetime_object:add()/datetime_object:sub() methods modify the
current object, while the +/- operators create a copy of the object
as the operation result.
When an interval operation is performed, each of the interval
subcomponents is calculated sequentially from the largest (year) to
the smallest (nsec):
year– yearsmonth– monthsweek– weeksday– dayshour– hoursmin– minutessec– secondsnsec– nanoseconds
If the result of the operation exceeds the allowed range for any of the components, an exception is raised.
The datetime and interval objects can participate in arithmetic
operations:
- The sum of two intervals is an interval object whose fields are the sum of each particular component of the operands.
- The result of subtracting two intervals is similar: it is an interval object where each subcomponent is the result of subtracting the corresponding fields of the original operands.
- Adding a datetime and an interval object produces a datetime object.
The addition is performed in a determined order – from the largest
component (
year) to the smallest (nsec). - Subtracting two datetime objects produces an interval object. The difference between two time values is calculated not as the difference of epoch seconds, but as the difference of all the subcomponents, that is, years, months, days, hours, minutes, and seconds.
- An untyped table object can be used in any context where typed
datetime or interval objects are used, if the left operand is a typed
object with an overloaded
+or-operation.
The matrix of eligible operands for addition and their result types:
datetime | interval | table | |
|---|---|---|---|
datetime | unsupported | datetime | datetime |
interval | datetime | interval | interval |
The matrix of eligible operands for subtraction and their result
types:
datetime | interval | table | |
|---|---|---|---|
datetime | interval | datetime | datetime |
interval | unsupported | interval | interval |
Addition and subtraction of datetime objects are performed taking
tzdata into account, if tzoffset or tz fields are set:
tarantool> datetime.new({tz='MSK'}) - datetime.new({tz='UTC'})---- -180 minutes
If you need to compare the values of datetime and interval objects,
you can use the standard Lua relational operators: ==, ~=, >, <,
>=, and <=. These operators use the overloaded __eq, __lt, and
__le metamethods to compare values.
Support for relational operators for interval objects has been added
since 2.11.0.
Example 1:
tarantool> dt1 = datetime.new({ year = 2010 })---tarantool> dt2 = datetime.new({ year = 2024 })---tarantool> dt1 == dt2---- falsetarantool> dt1 < dt2---- true
Example 2:
tarantool> iv1 = datetime.interval.new({month = 1})---tarantool> iv2 = datetime.interval.new({month = 2})---tarantool> iv1 < iv2---- true
Leap seconds are a periodic one-second adjustment of Coordinated Universal Time (UTC) in order to keep the system time of day close to the mean solar time. However, the Earth's rotation speed varies in response to climatic and geological events, and due to this, UTC leap seconds are irregularly and unpredictably spaced.
Tarantool includes the Time Zone
Database that besides the timezone
description files also contains a leap seconds file. You can use the
Lua module tarantool to get a used version of
tzdata.
The datetime module supports leap seconds at the most basic level:
-
The datetime.parse() function correctly parses an input string with 60 seconds:
tarantool> datetime.parse('23:12:60', {format ='%H:%M:%S'})---- 1970-01-01T23:13:00Z- 8... -
The datetime.new() function and the datetime_object:set() method accept a table with the
seckey set to 60 seconds:tarantool> datetime.new({ sec = 60 })---- 1970-01-01T00:01:00Z...
Meanwhile, the following cases are NOT supported by the datetime
module:
-
With the datetime.new() function, 60 leap seconds in the
seckey add an extra minute like regular seconds, and the result is represented in a regular manner, without leap seconds:tarantool> datetime.new({ year = 1998, month = 12, day = 31, hour = 23, min = 59, sec = 60})---- 1999-01-01T00:00:00Z... -
The datetime.parse() function returns an error when parsing an input string with a leap second (60 seconds) and a format that supports leap seconds ('rfc3339', 'iso8601'):
tarantool> datetime.parse('1998-12-31T23:59:60Z', {format='rfc3339'})---- error: 'builtin/datetime.lua:885: could not parse''1998-12-31T23:59:60Z'''...
Full support has been added since version 2.11.0.
Tarantool uses the Time Zone Database
(also known as the Olson database and supported by IANA) for timezone
support. You can use the Lua module tarantool to get
a used version of tzdata.
Every datetime object has three fields related to timezone support:
tz, tzoffset, and isdst:
-
The
isdstfield is calculated using tzindex and attributes of the selected timezone from the Olson database.tarantool> require('datetime').parse('2004-06-01T00:00 Europe/Moscow').isdst---- true... -
The
tzfield can take a timezone name or abbreviation. A timezone name is a human-readable name based on the Time Zone Database, for example, "Europe/Moscow". Timezone abbreviations represent time zones as alphabetic abbreviations such as "EST", "WST", and "F". Both timezone names and abbreviations are available via the bidirectional array datetime.TZ. -
The
tzoffsetfield is calculated automatically using the current Olson rule. This means that, for a given timezone name, information about summer time, leap years, and leap seconds is taken into account. However, thetzoffsetfield can be set manually if a suitable timezone is not available. Thetzandtzoffsetfields can be set in datetime.new(), datetime.parse(), and datetime_object:set(). Arithmetic operations on datetime objects are performed takingtzdatainto account, iftzoffsetortzfields are set (see the section interval_arithm).
-
The supported date range is from
-5879610-06-22to+5879611-07-11. -
There were periods in history when the local mean time in some timezones used an offset expressed not in whole minutes but in seconds. For example, in Moscow before 1918 the offset used was +2 hours 31 minutes 19 seconds. See an Olson dump for this period:
$ zdump -c1880,1918 -i Europe/MoscowTZ="Europe/Moscow"- +023017 MMT 1916-07-03 00:01:02 +023119 MMT 1917-07-02 00 +033119 MST 1 1917-12-27 23 +023119 MMTModern
tzdatarules do not use such tiny fractions, and all timezones differ from UTC by a value that is a multiple of minutes, not seconds. The datetime module in Tarantool uses minutes internally as units fortzoffset. So there might be some loss of precision when working with such old timestamps.