In SQL
date
, andtime
fields are converted to type the eXtremeDB typedatetime
for all operations. The only difference is how they are formatted for output. So, for example adate
fieldday
could be incrementedday+5
and the result will be of typedate
.For an overview see page Date, Time and Datetime Fields
The
date
,time
anddatetime
types are represented internally as integer values. When arithmetic is performed, the result will be of the original type, but the underlying value is used to perform arithmetic. So thedatetime
precision can be important. The default precision for xSQL is 1, i.e. 1 second. But it can be changed by thesetDateTimePrecision()
function. Regardless whether typedate
ordatetime
is used, seconds (or milliseconds, etc.) will be used in the operation.For example, consider the following operations:
XSQL>select cast('02-02-2013' as date); #1 ------------------------------------------------------------------------------ 02/02/2013 00:00:00 Selected records: 1 XSQL>select cast('02-02-2013' as time); #1 ------------------------------------------------------------------------------ 02/02/2013 00:00:00 Selected records: 1 XSQL>select cast('02-02-2013' as date) + 5; #1 ------------------------------------------------------------------------------ 02/02/2013 00:00:05 Selected records: 1 XSQL>select setDateTimePrecision(1000); #1 ------------------------------------------------------------------------------ 1 Selected records: 1 XSQL>select cast('02-02-2013' as date) + 5; #1 ------------------------------------------------------------------------------ 02/02/2013 00:00:00.005 Selected records: 1
Inserting Date and Time Data
Data can be inserted into date, time and datetime fields by specifying the date and time in a variety of string formats. (Currently on Windows systems, valid date values must have the year specified as greater than
1969
. (Note that on Unix-Linux platforms, and in the next release for Windows, thestrptime()
function will be used internally which does not have this limitation.)For example consider the following table:
XSQL>create table dt(d date, t time);Date and time values can be inserted with a string formatted "
M/D/Y h:m:s"
. If the value ofM
is greater than 1900, then the string is considered as"Y/M/D h:m:s
". For example:XSQL>insert into dt values( '7/10/1970 15:15:15', '23:23:23'); XSQL>insert into dt values( '1970/7/30', '0'); XSQL>select * from dt; d t --------------------------------------------------------------- 07/10/1970 15:15:15 23:23:23 07/30/1970 00:00:00 00:00:00Insert strings can also use the hyphen or dot separators, instead of slashes, for dates. For example:
XSQL>insert into dt(d) values( '6-10-1970'); XSQL>insert into dt(d) values( '1970.7.30'); XSQL>select * from dt; d t --------------------------------------------------------------- 06/10/1970 00:00:00 00:00:00 07/30/1970 00:00:00 00:00:00Another alternative is to use abbreviations (first three letters) for the month with hyphen separators; i.e. a string with format
"D-MON-Y h:m:s"
. For example:XSQL>insert into dt(d) values( '30-sep-1970'); XSQL>select * from dt; d t --------------------------------------------------------------- 09/30/1970 00:00:00 nullNote that the month integer value
M
must be a month number starting from 1 for January, and the year valueY
can be 4 digit integer greater than 1900; otherwise, if the value ofY
is less than50
it is considered as a2000+
year, if greater than or equal to50
it is considered a1900+
year. For example:XSQL>insert into dt(d) values( '30-aug-20'); XSQL>insert into dt(d) values( '30-aug-80'); XSQL>select * from dt; d t --------------------------------------------------------------- 08/30/2020 00:00:00 null 08/30/1980 00:00:00 nullThe hour
h
and minutem
values must be integers less than24
and60
respectively and secondss
can be expressed as an integer or floating point value, however floating point fractional values are truncated. For example:XSQL>insert into dt(t) values( '23:59:19.6'); XSQL>select * from dt; d t --------------------------------------------------------------- null 23:59:19If a time part is not supplied, the string is considered as a date and the time part is set as zero. If the string could not be successfully parsed as a date, then the time format
"h:m:s"
is tried.
Storing and Manipulating High-definition Datetime Data
When using high-definition data, for instance timestamp fields with millisecond granularity, it is recommended to use the
bigint
data type. It is possible to use achar(9)
type field to store a timestamp, for examplecreate table DailyQuotesIN (tTime char(9), ...)The eXtremeSQL runtime will implicitly perform the conversion from a
char(9)
to aninteger
-- no explicit casts of input data are required. However, from the performance standpoint it is preferable to use thebigint
data type:create table DailyQuotesIN (tTime bigint, ...)Using the
bigint
data type you would simply loadtTime
data with the time encoded as an integer value like093515984593000
and perform any manipulations with this data directly, including various forms of output. Note however that to extract some part of the field representing a time (for example the hour or minute), standard SQL functions should not be used; i.e. do not use the SQL functionhour()
orminute()
. Instead use integer division. For example:select tTime / 10000000000 as hour, tTime / 100000000 % 100 as minute, real(tTime % 10000000000) / 100000000 as second from DailyQuotesIN;
Converting Date to Integer
When using variables of type Date it can be useful to convert the Date value to a long integer value representing the number of milliseconds since January 1, 1970, 00:00:00 GMT. This can be done by using the Date method
getTime()
. The following code snippet demonstrates how this method might be used (in Java):{ Calendar cal = Calendar.getInstance(); cal.set(2014, 1, 1, 9, 30); cal.set(2014, 12, 30, 16, 00); Date dstart = cal.getTime(); Date dfinish = cal.getTime(); long start = dstart.getTime(); long finish = dfinish.getTime(); System.out.println("Calculating high bids over symbols from time " + start + " to " + finish + ":"); SqlResultSet res = conn.executeQuery("SELECT Symbol, seq_ignore(seq_search(qTime, ?, ?)) as t, seq_max (Bid@t) FROM Quotes", start, finish);Implementation details
Given the embedded nature of the eXtremeDB, the datetime core data type is stored as a 8-byte integer and allows all integer operations such as addition and subtraction. The datetime type is interpreted by applications, and could represent for example the epoch time in seconds, or the time in CPU ticks since the device was turned on, etc., That said, the higher-level eXtremeDB components such as Java and Python wrapper APIs, SQL API and xSQL server assume that the datetime type is interpreted as a UTC timestamp: the UNIX epoch time.
Epoch, by definition, is a point in time that is used as a reference point for measuring time. It doesn’t necessarily have to have a specific meaning. January, 1 1970 known as the Unix epoch time is used by many Unix-like systems and programming languages, such as C/C++, Java, JavaScript, Perl, PHP, Python, etc. The Unix epoch 0 is at 00:00:00 UTC on 1 January 1970, so systems use a negative number to represent any timestamp before that.
Since Unix time increments every second, and as an alternative to using a different data type to represent time with greater precision, the eXtremeDB adds a property to the datetime type called "datetime precision”. The precision property numerically represents the number of ticks per second. The default value for it is 1, which means that the database stores a datetime value as the number of seconds since the epoch (i.e. 00:00:00 UTC 1 January 1970). However the resolution of datetime fields can be changed by an application to a resolution ranging from 1 (to store the number of seconds) to 1000000000 (for the number of nanoseconds).
For example the epoch time for the "2023-07-04 12:00:00 GMT” date is equal to 1688472000. If the
dt_precision
is set to 1000 indicating the milliseconds resolution, the eXtremeDB database would represent it as 1.688.472.000.000The algorithm used by the
SQL INSERT
operator is as follows:The date string is parsed into the C language time structure that contains a calendar date and time broken down into its components. The structure contains nine members of type int (in any order), which are:
MemberTypeMeaningtm_secintseconds after the minutetm_minintminutes after the hourtm_hourinthours since midnighttm_mdayintday of the monthtm_monintmonths since Januarytm_yearintyears sincetm_wdayintdays since Sundaytm_ydayintdays since January 1tm_isdstintDaylight Saving TimeThe eXtremeDB sets the
tm_isdst
to -1 indicating that the Daylight Saving Time information is not available. The tm structure is then passed to the C runtimemktime()
function that converts the time into the UNIX epoch representation in the current time zone (all time zones are defined as offsets from UTC ). Finally the value is multiplied by the "datetime precision”.Conversely, when the SQL engine reconstructs the stored datetime value back into string, the stored value is divided by the set precision, receiving the epoch time in seconds. Then the epoch time is passed into the C runtime
localtime()
function that fills out the tm strcuture in the current time zone and the tm structure values are then represented in a form of a formatted string.Even though most systems in the world use Unix time, it has limitations. On some embedded operating systems such as QNX 7.0, the
mktime()
function doesn't support dates below 01/01/1970 (i.e. does not work with negative epoch time). In these cases the eXtremeDB makes use of the time-shift technique that essentially up-shifts all dates below the year 1970 to a predefine number of years, then converts the dates through themktime()
and then downshifts the value back prior to storing it in the database. Thus the database runtime keeps all dates passed 1970 as theepoch_time * datetime_precision
value while dates prior to 1970 are kept as negative numbers. When applications read dates back, the process is reversed. Note that these values could be off from the epoch time by the date light saving time value (usually one hour) because of different daylight saving rules applied in different calendar years. However, the conversion from the input string into the internal storage representation and back into the string is preserved.Furthermore, some applications benefit from interpreting datetime as intervals in seconds/milliseconds/nanoseconds as opposed to absolute dates. In this case the stored 8-byte value would be formatted as hours:minutes:seconds. In order to accommodate these scenarios it is possible to define an interval from 1/1/1970 forward within which the stored datetime translates to time interval. By default the interval value is zero (all dates are viewed as calendar dates). The SQL function
setMaxInterval(n_sec)
or the xSQL commandmaxinterval n_sec
are used to adjust the length of the interval. For examplemaxinterval 86400
instructs the xSQL to interpret all dates 24 hours forward and back from the 1/1/1970 as time interval (note that the referenced values could be negative, which is helpful when arithmetic operations over time values are performed)