KDB knowledge

Date and time functions

Take a time apart, find the weekday, quarter and week, cut, add and build times, count days or months between times, fiscal years (also Nepal's), and write a time as text.

KDB keeps a TIMESTAMP as the number of milliseconds (1/1000 of a second) since 1970-01-01, in UTC. UTC is the world clock time with no time zone. A local time is UTC plus its zone offset: Nepal is +05:45 (11:00 in Kathmandu is 05:15 UTC), New York is -04:00 in summer (07:00 there is 11:00 UTC).

Example: CITY volume per Nepal clock hour (sample data: sample)

SELECT hour(time + 20700000) AS nepal_hour,
       count(*) AS candles,
       sum(volume) AS volume
FROM ochl_minutes
WHERE symbol = 'CITY' AND time IN '2026-09-10'
GROUP BY hour(time + 20700000)
ORDER BY nepal_hour;

Result:

nepal_hour (LONG)candles (LONG)volume (DOUBLE)
116047020
126041230
136046180
146048610

(4 rows)

now, systimestamp

Syntax:

now()
systimestamp()

The current time. systimestamp is the same function.

Example

SELECT now() > '2026-01-01' AS after_2026, now() = systimestamp() AS same_time, year(now()) >= 2026 AS year_ok;

Result:

after_2026 (BOOL)same_time (BOOL)year_ok (BOOL)
truetruetrue

(1 row)

Example: Save the login time of an app user

Setup:

CREATE TABLE logins (user_id INT, logged_in_at TIMESTAMP DEFAULT now());
INSERT INTO logins (user_id) VALUES (7);
SELECT user_id, logged_in_at > '2026-01-01' AS has_time FROM logins;

Result:

user_id (INT)has_time (BOOL)
7true

(1 row)

Example: The PostgreSQL names give the same time

SELECT now() = current_timestamp AS same_1, now() = current_timestamp() AS same_2, now() = localtimestamp AS same_3;

Result:

same_1 (BOOL)same_2 (BOOL)same_3 (BOOL)
truetruetrue

(1 row)

Example: getdate is not KDB SQL (shows an error)

SELECT getdate();

Result:

Error: line 1, column 8: unknown function 'getdate'

year

Syntax:

year(t)

The year of the UTC date: year('2026-09-10') is 2026.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT year('2026-09-10T08:30:15Z') AS a, year(CAST('2025-12-31' AS DATE)) AS b, year('2026-01-01T02:00:00+05:45') AS nepal_new_year, year(NULL) AS c;

Result:

a (LONG)b (LONG)nepal_new_year (LONG)c (STRING)
202620252025NULL

(1 row)

Example: Average CITY close per year (sample data: sample)

SELECT year(time) AS year, round(avg(close), 2) AS avg_close, count(*) AS days
FROM ochl_day
WHERE symbol = 'CITY'
GROUP BY year(time)
ORDER BY year;

Result:

year (LONG)avg_close (DOUBLE)days (LONG)
2025540.94
2026504.0515

(2 rows)

Example: Text that is not a full date (shows an error)

SELECT year('2026-09');

Result:

Error: line 1, column 8: year: argument 1 must be a time, got '2026-09'

month

Syntax:

month(t)

The month of the UTC date, from 1 (January) to 12 (December).

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT month('2026-09-10') AS a, month(CAST('2025-12-28' AS DATE)) AS b;

Result:

a (LONG)b (LONG)
912

(1 row)

Example: Month report: trading days and volume per symbol (sample data: sample)

SELECT year(time) AS year, month(time) AS month, symbol,
       count(*) AS days, sum(volume) AS volume
FROM ochl_day
WHERE symbol IN ('CITY', 'VOLT')
GROUP BY year(time), month(time), symbol
ORDER BY year, month, symbol;

Result:

year (LONG)month (LONG)symbol (SYMBOL)days (LONG)volume (DOUBLE)
202512CITY4255090
202512VOLT4409650
20268CITY7855550
20268VOLT7677070
20269CITY8876210
20269VOLT8713310

(6 rows)

day

Syntax:

day(t)

The day of the month of the UTC date, from 1 to 31.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT day('2026-09-10T20:00:00Z') AS a, day('2026-09-02T02:30:00+05:45') AS utc_day, day(CAST('2026-09-02T02:30:00+05:45' AS TIMESTAMP) + 20700000) AS nepal_day;

Result:

a (LONG)utc_day (LONG)nepal_day (LONG)
1012

(1 row)

Example: App sign-ups per day: the UTC day and the Nepal day (sample data: fn-dates)

SELECT day(created_at) AS utc_day, day(created_at + 20700000) AS nepal_day, count(*) AS signups
FROM signups
GROUP BY day(created_at), day(created_at + 20700000)
ORDER BY nepal_day, utc_day;

Result:

utc_day (LONG)nepal_day (LONG)signups (LONG)
113
121
221
333
441
661

(6 rows)

hour

Syntax:

hour(t)

The hour of the UTC time, from 0 to 23.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT hour('2026-09-10 11:00:00') AS no_zone_is_utc, hour('2026-09-10T11:00:00+05:45') AS nepal_11_in_utc, hour(CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) + 20700000) AS nepal_hour;

Result:

no_zone_is_utc (LONG)nepal_11_in_utc (LONG)nepal_hour (LONG)
11511

(1 row)

Example: Forum posts per Nepal hour of the day (sample data: fn-dates)

SELECT hour(created_at + 20700000) AS nepal_hour, count(*) AS posts
FROM forum_posts
GROUP BY hour(created_at + 20700000)
ORDER BY posts DESC, nepal_hour
LIMIT 5;

Result:

nepal_hour (LONG)posts (LONG)
102
112
142
81
91

(5 rows)

minute

Syntax:

minute(t)

The minute of the UTC time, from 0 to 59.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT minute('2026-09-10T11:07:30+05:45') AS utc_minute, minute(CAST('2026-09-10T11:07:30+05:45' AS TIMESTAMP) + 20700000) AS nepal_minute;

Result:

utc_minute (LONG)nepal_minute (LONG)
227

(1 row)

Example: COAST candles in the first 5 minutes of the day (Nepal 11:00-11:04) (sample data: sample)

SELECT time, open, close
FROM ochl_minutes
WHERE symbol = 'COAST' AND time IN '2026-09-10'
  AND hour(time + 20700000) = 11 AND minute(time + 20700000) < 5;

Result:

time (TIMESTAMP)open (DOUBLE)close (DOUBLE)
2026-09-10T05:15:00.000Z380.1380
2026-09-10T05:16:00.000Z380379.6
2026-09-10T05:17:00.000Z379.6380.1
2026-09-10T05:18:00.000Z380.1380.4
2026-09-10T05:19:00.000Z380.4380.7

(5 rows)

second

Syntax:

second(t)

The second of the UTC time, from 0 to 59. Milliseconds are not included.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT second('2026-09-10T11:00:59.999Z') AS a, second('2026-09-10T11:00:05+05:45') AS b;

Result:

a (LONG)b (LONG)
595

(1 row)

day_of_week

Syntax:

day_of_week(t)

The weekday of the UTC date as a number: 0 = Sunday, 1 = Monday, ... 6 = Saturday.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT day_of_week('2026-09-06') AS sunday, day_of_week('2026-09-10') AS thursday, day_of_week(CAST('2026-09-12' AS DATE)) AS saturday;

Result:

sunday (LONG)thursday (LONG)saturday (LONG)
046

(1 row)

Example: Trading days per weekday (a Sunday-to-Thursday week) (sample data: sample)

SELECT day_of_week(time) AS dow, count(*) AS candles, round(avg(volume)) AS avg_volume
FROM ochl_day
GROUP BY day_of_week(time)
ORDER BY dow;

Result:

dow (LONG)candles (LONG)avg_volume (DOUBLE)
01297458
11291830
21283335
31296533
49114613

(5 rows)

is_trading_day

Syntax:

is_trading_day(t)

true when the UTC date is a Sunday, Monday, Tuesday, Wednesday or Thursday: a Sunday-to-Thursday trading week, as on some exchanges. false on Friday and Saturday.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT is_trading_day('2026-09-10') AS thursday, is_trading_day('2026-09-11') AS friday, is_trading_day('2026-09-12') AS saturday, is_trading_day('2026-09-13') AS sunday;

Result:

thursday (BOOL)friday (BOOL)saturday (BOOL)sunday (BOOL)
truefalsefalsetrue

(1 row)

Example: App sign-ups on trading days and on the weekend (Nepal date) (sample data: fn-dates)

SELECT is_trading_day(created_at + 20700000) AS trading_day, count(*) AS signups
FROM signups
GROUP BY is_trading_day(created_at + 20700000)
ORDER BY trading_day;

Result:

trading_day (BOOL)signups (LONG)
false1
true9

(2 rows)

date_part, extract

Syntax:

date_part(field, t)
extract(field FROM t)
extract(field, t)

Takes one part of a time: the year, the month, the hour, the weekday, the week number and so on. date_part('month', '2026-09-10') is 9. extract(month FROM t) is the SQL standard way to write the same thing; extract('month', t) also works.

ArgumentTypeMeaning
fieldtext (a word after extract)the part you want; see the table below (any case, years, months, ... also work)
tTIMESTAMP, DATE, time text or millisecondsthe time
FieldGives2026-09-10 05:20:30.250 UTC gives
yearthe year2026
quarterquarter of the year, 1-43
month1-129
weekISO week number, 1-53 (see week_of_year)37
dayday of the month, 1-3110
dowweekday, 0 = Sunday ... 6 = Saturday4
isodowweekday, 1 = Monday ... 7 = Sunday4
doyday of the year, 1-366253
hour0-235
minute0-5920
secondseconds with the milliseconds, as a DOUBLE30.25
millisecondthe seconds counted in milliseconds, 0-5999930250
epochseconds since 1970-01-01 UTC, as a DOUBLE1789017630.25
isoyearthe year the ISO week belongs to2026
decadethe year / 10202
centurythe century21

Example

SELECT date_part('year', '2026-09-10T05:20:30.250Z') AS year,
       extract(month FROM '2026-09-10T05:20:30.250Z') AS month,
       extract('dow', '2026-09-10') AS dow,
       date_part('isodow', '2026-09-13') AS isodow_sunday,
       date_part('doy', CAST('2026-09-10' AS DATE)) AS doy,
       date_part('second', '2026-09-10T05:20:30.250Z') AS second,
       date_part('epoch', '2026-09-10T00:00:00Z') AS epoch;

Result:

year (LONG)month (LONG)dow (LONG)isodow_sunday (LONG)doy (LONG)second (DOUBLE)epoch (DOUBLE)
202694725330.251788998400

(1 row)

Example: App sales per year and quarter (sample data: analysis-finance)

SELECT extract(year FROM invoice_date) AS year, extract(quarter FROM invoice_date) AS quarter,
       count(*) AS invoices, sum(amount) AS sales
FROM invoices
GROUP BY extract(year FROM invoice_date), extract(quarter FROM invoice_date)
ORDER BY year, quarter;

Result:

year (LONG)quarter (LONG)invoices (LONG)sales (DECIMAL(2))
20252112000.00
20253315000.00
2025414500.00
20261213500.00
2026214500.00
20263430000.00

(6 rows)

Example: Traded volume per Nepal weekday (0 = Sunday) (sample data: sample)

SELECT date_part('dow', time + 20700000) AS nepal_weekday, count(*) AS minutes, sum(volume) AS volume
FROM ochl_minutes
GROUP BY date_part('dow', time + 20700000)
ORDER BY nepal_weekday;

Result:

nepal_weekday (LONG)minutes (LONG)volume (DOUBLE)
3480368720
4476369240

(2 rows)

Example: An unknown field lists the fields you can use (shows an error)

SELECT date_part('fortnight', '2026-09-10');

Result:

Error: line 1, column 8: date_part: unknown field 'fortnight'; use year, quarter, month, week, day, dow, isodow, doy, hour, minute, second, millisecond, epoch, isoyear, decade or century

quarter

Syntax:

quarter(t)

The quarter of the year of the UTC date: 1 for January-March, 2 for April-June, 3 for July-September, 4 for October-December. For a fiscal year that does not start in January, use fiscal_quarter.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT quarter('2026-01-01') AS jan, quarter('2026-06-30') AS jun, quarter('2026-09-10T05:15:00Z') AS sep, quarter(CAST('2026-12-31' AS DATE)) AS dec;

Result:

jan (LONG)jun (LONG)sep (LONG)dec (LONG)
1234

(1 row)

Example: Volume of every symbol per quarter (sample data: sample)

SELECT year(time) AS year, quarter(time) AS quarter, symbol, count(*) AS days, sum(volume) AS volume
FROM ochl_day
GROUP BY year(time), quarter(time), symbol
ORDER BY year, quarter, symbol;

Result:

year (LONG)quarter (LONG)symbol (SYMBOL)days (LONG)volume (DOUBLE)
20254CITY4255090
20254COAST4206980
20254VOLT4409650
20263CITY151731760
20263COAST151467530
20263VOLT151390380

(6 rows)

day_of_year

Syntax:

day_of_year(t)

The day number in the year of the UTC date: 1 for 1 January, 365 for 31 December (366 in a leap year).

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT day_of_year('2026-01-01') AS first_day, day_of_year('2026-09-10') AS today, day_of_year('2026-12-31') AS last_day, day_of_year(CAST('2024-12-31' AS DATE)) AS leap_year;

Result:

first_day (LONG)today (LONG)last_day (LONG)leap_year (LONG)
1253365366

(1 row)

Example: How much of the year had passed on each candle day? (sample data: sample)

SELECT time, day_of_year(time) AS day_no, round(day_of_year(time) * 100.0 / 365, 1) AS year_done_pct
FROM ochl_day
WHERE symbol = 'CITY' AND time >= '2026-09-08'
ORDER BY time;

Result:

time (TIMESTAMP)day_no (LONG)year_done_pct (DOUBLE)
2026-09-08T00:00:00.000Z25168.8
2026-09-09T00:00:00.000Z25269
2026-09-10T00:00:00.000Z25369.3

(3 rows)

week_of_year

Syntax:

week_of_year(t)

The ISO week number of the UTC date, from 1 to 53. ISO weeks start on Monday, and week 1 is the week that has the first Thursday of the year. So the first days of January can be in week 52 or 53 of the year before, and the last days of December in week 1 of the next year.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT week_of_year('2026-09-10') AS thursday, week_of_year('2026-01-01') AS new_year_2026,
       week_of_year('2027-01-01') AS new_year_2027, date_part('isoyear', '2027-01-01') AS its_iso_year;

Result:

thursday (LONG)new_year_2026 (LONG)new_year_2027 (LONG)its_iso_year (LONG)
371532026

(1 row)

Example: Forum posts per ISO week (sample data: fn-dates)

SELECT date_part('isoyear', created_at) AS iso_year, week_of_year(created_at) AS week, count(*) AS posts
FROM forum_posts
GROUP BY date_part('isoyear', created_at), week_of_year(created_at)
ORDER BY iso_year, week;

Result:

iso_year (LONG)week (LONG)posts (LONG)
2026331
2026343
2026354
2026363
2026373

(5 rows)

date_trunc

Syntax:

date_trunc(unit, t)
date_trunc(unit, t, time_zone)

Cuts the time down to the start of its year, month, week, day, hour, minute or second. date_trunc('month', '2026-09-10T08:30:00Z') is 2026-09-01T00:00:00.000Z. Use it to put rows into groups by time.

ArgumentTypeMeaning
unittext'year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second' or 'ms' (any case). Short and plural forms also work: 'd', 'h', 'm' (minute), 's', 'days', 'hours', ...
tTIMESTAMP, DATE, time text or millisecondsthe time
time_zonetextoptional: cut on this zone's clock, like 'Asia/Kathmandu' or '+05:45' (the PostgreSQL form). The zone names are the same as for SAMPLE BY.

Example

SELECT date_trunc('year', '2026-09-10T08:30:00Z') AS year, date_trunc('month', '2026-09-10T08:30:00Z') AS month, date_trunc('week', '2026-09-10T08:30:00Z') AS week_sunday, date_trunc('hour', '2026-09-10T08:30:00Z') AS hour, date_trunc('month', CAST('2026-09-10' AS DATE)) AS date_stays_date;

Result:

year (TIMESTAMP)month (TIMESTAMP)week_sunday (TIMESTAMP)hour (TIMESTAMP)date_stays_date (DATE)
2026-01-01T00:00:00.000Z2026-09-01T00:00:00.000Z2026-09-06T00:00:00.000Z2026-09-10T08:00:00.000Z2026-09-01

(1 row)

Example: Forum posts per week (sample data: fn-dates)

SELECT date_trunc('week', created_at) AS week, count(*) AS posts, count(DISTINCT author) AS authors
FROM forum_posts
GROUP BY date_trunc('week', created_at)
ORDER BY week;

Result:

week (TIMESTAMP)posts (LONG)authors (LONG)
2026-08-16T00:00:00.000Z33
2026-08-23T00:00:00.000Z44
2026-08-30T00:00:00.000Z33
2026-09-06T00:00:00.000Z44

(4 rows)

Example: Monthly candles of CITY from daily candles (sample data: sample)

SELECT date_trunc('month', time) AS month,
       first(open) AS open, max(high) AS high, min(low) AS low, last(close) AS close
FROM ochl_day
WHERE symbol = 'CITY'
GROUP BY date_trunc('month', time)
ORDER BY month;

Result:

month (TIMESTAMP)open (DOUBLE)high (DOUBLE)low (DOUBLE)close (DOUBLE)
2025-12-01T00:00:00.000Z540.3546.2536.4542.4
2026-08-01T00:00:00.000Z505517500.1505.7
2026-09-01T00:00:00.000Z504.9512.4494.1504.9

(3 rows)

Example: 'week' and 'w' are different

SELECT date_trunc('week', '2026-09-10') AS week_from_sunday, date_trunc('w', '2026-09-10') AS w_from_thursday;

Result:

week_from_sunday (TIMESTAMP)w_from_thursday (TIMESTAMP)
2026-09-06T00:00:00.000Z2026-09-10T00:00:00.000Z

(1 row)

Example: Start of the quarter: sales per quarter (sample data: analysis-finance)

SELECT date_trunc('quarter', invoice_date) AS quarter_start, count(*) AS invoices, sum(amount) AS sales
FROM invoices
GROUP BY date_trunc('quarter', invoice_date)
ORDER BY quarter_start;

Result:

quarter_start (TIMESTAMP)invoices (LONG)sales (DECIMAL(2))
2025-04-01T00:00:00.000Z112000.00
2025-07-01T00:00:00.000Z315000.00
2025-10-01T00:00:00.000Z14500.00
2026-01-01T00:00:00.000Z213500.00
2026-04-01T00:00:00.000Z14500.00
2026-07-01T00:00:00.000Z430000.00

(6 rows)

Example: Decade is not a unit (shows an error)

SELECT date_trunc('decade', '2026-09-10');

Result:

Error: line 1, column 8: date_trunc: unit must be year, month, week, day, hour, minute, second or ms

Example: The UTC day and the Nepal day of the same moments

SELECT t, date_trunc('day', t) AS utc_midnight, date_trunc('day', t, 'Asia/Kathmandu') AS nepal_midnight,
       date_trunc('month', t, 'Asia/Kathmandu') AS nepal_month
FROM (SELECT CAST('2026-09-09T20:00:00Z' AS TIMESTAMP) AS t
      UNION ALL SELECT CAST('2026-08-31T19:00:00Z' AS TIMESTAMP)) x
ORDER BY t;

Result:

t (TIMESTAMP)utc_midnight (TIMESTAMP)nepal_midnight (TIMESTAMP)nepal_month (TIMESTAMP)
2026-08-31T19:00:00.000Z2026-08-31T00:00:00.000Z2026-08-31T18:15:00.000Z2026-08-31T18:15:00.000Z
2026-09-09T20:00:00.000Z2026-09-09T00:00:00.000Z2026-09-09T18:15:00.000Z2026-08-31T18:15:00.000Z

(2 rows)

Example: Sign-ups per Nepal day, as times (sample data: fn-dates)

SELECT date_trunc('day', created_at, 'Asia/Kathmandu') AS nepal_day, count(*) AS signups
FROM signups
GROUP BY date_trunc('day', created_at, 'Asia/Kathmandu')
ORDER BY nepal_day;

Result:

nepal_day (TIMESTAMP)signups (LONG)
2026-08-31T18:15:00.000Z3
2026-09-01T18:15:00.000Z2
2026-09-02T18:15:00.000Z3
2026-09-03T18:15:00.000Z1
2026-09-05T18:15:00.000Z1

(5 rows)

timestamp_floor

Syntax:

timestamp_floor(unit, t)
timestamp_floor(unit, t, time_zone)
timestamp_floor(unit, t, origin)

The QuestDB function: cuts the time down to a whole number of units. timestamp_floor('15m', '2026-09-10T05:22:10Z') is 2026-09-10T05:15:00.000Z.

ArgumentTypeMeaning
unittextan optional count and one letter: T millisecond, s second, m minute, h hour, d day, w week, M month, y year. '15m', '4h', '1d', 'M'. Upper and lower case matter (m minute, M month).
tTIMESTAMP, DATE, time text or millisecondsthe time
time_zonetextoptional: cut on this zone's clock, like 'Asia/Kathmandu' or '+05:45'
origina timeoptional instead of a zone: count the units from this time, not from 1970-01-01

Example: Cut one moment by several units

SELECT timestamp_floor('15m', '2026-09-10T05:22:10Z') AS quarter_hour,
       timestamp_floor('1d', '2026-09-09T20:00:00Z') AS utc_day,
       timestamp_floor('1d', '2026-09-09T20:00:00Z', 'Asia/Kathmandu') AS nepal_day,
       timestamp_floor('w', '2026-09-10T05:00:00Z') AS monday,
       timestamp_floor('3M', '2026-09-10T05:00:00Z') AS quarter_month,
       timestamp_floor('2d', '2026-09-10T05:00:00Z', '2026-09-01') AS two_days_from_sep_1;

Result:

quarter_hour (TIMESTAMP)utc_day (TIMESTAMP)nepal_day (TIMESTAMP)monday (TIMESTAMP)quarter_month (TIMESTAMP)two_days_from_sep_1 (TIMESTAMP)
2026-09-10T05:15:00.000Z2026-09-09T00:00:00.000Z2026-09-09T18:15:00.000Z2026-09-07T00:00:00.000Z2026-07-01T00:00:00.000Z2026-09-09T00:00:00.000Z

(1 row)

Example: Nepal-hour candles with timestamp_floor, like SAMPLE BY 1h TIME ZONE (sample data: sample)

SELECT timestamp_floor('1h', time, 'Asia/Kathmandu') AS hour, first(open) AS open, last(close) AS close, count(*) AS minutes
FROM ochl_minutes
WHERE symbol = 'CITY' AND time IN '2026-09-10'
GROUP BY timestamp_floor('1h', time, 'Asia/Kathmandu')
ORDER BY hour;

Result:

hour (TIMESTAMP)open (DOUBLE)close (DOUBLE)minutes (LONG)
2026-09-10T05:15:00.000Z504.6505.360
2026-09-10T06:15:00.000Z505.3502.760
2026-09-10T07:15:00.000Z502.7502.660
2026-09-10T08:15:00.000Z502.6504.960

(4 rows)

Example: An unknown unit (shows an error)

SELECT timestamp_floor('1x', '2026-09-10');

Result:

Error: line 1, column 8: timestamp_floor: unit must be T, s, m, h, d, w, M or y with an optional count, like '15m' or '1d'; got '1x'

timestamp_floor_utc(unit, t [, zone]) is QuestDB's name for the same function: its answer is in UTC, and KDB's always is.

timestamp_ceil

Syntax:

timestamp_ceil(unit, t)
timestamp_ceil(unit, t, time_zone)
timestamp_ceil(unit, t, origin)

The QuestDB function: moves the time up to the next whole unit. A time that is already on a whole unit stays as it is: timestamp_ceil('1h', '06:00') is 06:00.

ArgumentTypeMeaning
unittextas for timestamp_floor: '15m', '1h', '1d', 'M', ...
ta timethe time
time_zone or origintext or a timeoptional, as for timestamp_floor

Example: Round up to the quarter hour, the day and the month

SELECT timestamp_ceil('15m', '2026-09-10T05:22:10Z') AS quarter_hour,
       timestamp_ceil('15m', '2026-09-10T05:30:00Z') AS already_whole,
       timestamp_ceil('1d', '2026-09-10T05:22:10Z') AS next_midnight,
       timestamp_ceil('M', '2026-09-10T05:22:10Z') AS next_month;

Result:

quarter_hour (TIMESTAMP)already_whole (TIMESTAMP)next_midnight (TIMESTAMP)next_month (TIMESTAMP)
2026-09-10T05:30:00.000Z2026-09-10T05:30:00.000Z2026-09-11T00:00:00.000Z2026-10-01T00:00:00.000Z

(1 row)

today, yesterday, tomorrow

Syntax:

today()
today(time_zone)
today(t)
yesterday(...)
tomorrow(...)

QuestDB's day intervals: the whole day, from 00:00 to 23:59:59.999. Use them after IN: WHERE time IN today() (interval lists).

ArgumentTypeMeaning
time_zonetextoptional: the day on this zone's clock, like 'Asia/Kathmandu'
ta timeoptional: the day of this time instead of now

Example: Today's rows, and the start of tomorrow (sample data: sample)

SELECT count(*) AS rows_today, interval_start(tomorrow()) AS tomorrow_starts
FROM live_data WHERE timestamp IN today();

Result:

rows_today (LONG)tomorrow_starts (TIMESTAMP)
02026-10-23T00:00:00.000Z

(1 row)

Example: The day of a given time, and the day before it

SELECT today('2026-09-10T20:00:00Z') AS that_day, interval_start(yesterday('2026-09-10T20:00:00Z')) AS day_before;

Result:

that_day (STRING)day_before (TIMESTAMP)
('2026-09-10T00:00:00.000Z', '2026-09-10T23:59:59.999Z')2026-09-09T00:00:00.000Z

(1 row)

interval, interval_start, interval_end

Syntax:

interval(from, to)
interval_start(an_interval)
interval_end(an_interval)

interval makes a QuestDB interval from two times, both included. interval_start and interval_end give its first and last moment.

ArgumentTypeMeaning
from, toa timethe first and the last moment; to must not be before from
an_intervaltextan interval from interval(), today(), yesterday() or tomorrow()

Example: An interval and its two ends

SELECT interval('2026-09-10T05:15:00Z', '2026-09-10T09:15:00Z') AS session,
       interval_start(interval('2026-09-10T05:15:00Z', '2026-09-10T09:15:00Z')) AS opens,
       interval_end(interval('2026-09-10T05:15:00Z', '2026-09-10T09:15:00Z')) AS closes;

Result:

session (STRING)opens (TIMESTAMP)closes (TIMESTAMP)
('2026-09-10T05:15:00.000Z', '2026-09-10T09:15:00.000Z')2026-09-10T05:15:00.000Z2026-09-10T09:15:00.000Z

(1 row)

Example: The end must not be before the start (shows an error)

SELECT interval('2026-09-10', '2026-09-09');

Result:

Error: line 1, column 8: interval: the end 2026-09-09T00:00:00.000Z is before the start 2026-09-10T00:00:00.000Z

days_in_month, is_leap_year, is_end_of_month, day_of_week_sunday_first, millis, to_pg_date

Syntax:

days_in_month(t)
is_leap_year(t)
is_leap_year(year)
is_end_of_month(t)
day_of_week_sunday_first(t)
millis(t)
to_pg_date(t)

Small QuestDB calendar functions.

FunctionReturns
days_in_month(t)the days in the month of t: 28 to 31
is_leap_year(t)true when the year of t (or the year number) has 29 February
is_end_of_month(t)true on the last day of the month
day_of_week_sunday_first(t)1 Sunday, 2 Monday, ... 7 Saturday
millis(t)the milliseconds of the second: 0 to 999
to_pg_date(t)the day of t as a DATE

Example: Facts about a date

SELECT days_in_month('2028-02-10') AS feb_2028_days,
       is_leap_year('2028-02-10') AS leap_2028,
       is_leap_year(2026) AS leap_2026,
       is_end_of_month('2026-09-30') AS month_end,
       day_of_week_sunday_first('2026-09-27') AS sunday,
       millis('2026-09-10T05:15:00.250Z') AS ms,
       to_pg_date('2026-09-10T20:00:00Z') AS day;

Result:

feb_2028_days (LONG)leap_2028 (BOOL)leap_2026 (BOOL)month_end (BOOL)sunday (LONG)ms (LONG)day (DATE)
29truefalsetrue12502026-09-10

(1 row)

sysdate

Syntax:

sysdate()

QuestDB's clock: the time now, the same as now().

Example: sysdate is now

SELECT sysdate() = now() AS same;

Result:

same (BOOL)
true

(1 row)

timestamp_sequence, timestamp_shuffle

Syntax:

timestamp_sequence(start, step_microseconds)
timestamp_shuffle(from, to)

QuestDB's test-data helpers. timestamp_sequence gives start on the first row, start + step on the next, and so on. timestamp_shuffle gives a random time from from to to.

ArgumentTypeMeaning
starta timethe first time
step_microsecondswhole numberthe step, in microseconds as in QuestDB (60000000 is one minute); KDB keeps milliseconds, so the time is cut to the millisecond
from, toa timethe range for a random time, both ends included

Example: One row a minute, with long_sequence

SELECT x, timestamp_sequence('2026-09-10T05:15:00Z', 60000000) AS time
FROM long_sequence(4);

Result:

x (LONG)time (TIMESTAMP)
12026-09-10T05:15:00.000Z
22026-09-10T05:16:00.000Z
32026-09-10T05:17:00.000Z
42026-09-10T05:18:00.000Z

(4 rows)

Example: Random times in one day

SELECT count(*) AS inside FROM (SELECT timestamp_shuffle('2026-09-10', '2026-09-11') AS t FROM long_sequence(100)) s
WHERE t >= '2026-09-10' AND t <= '2026-09-11';

Result:

inside (LONG)
100

(1 row)

to_timezone, to_utc

Syntax:

to_timezone(t, time_zone)
to_utc(t, time_zone)

The QuestDB functions. to_timezone shows a UTC time on the clock of a zone: to_timezone('2026-09-10T05:15:00Z', 'Asia/Kathmandu') is 2026-09-10T11:00:00.000Z. to_utc is the other way round: it reads t as that zone's clock and gives the UTC time.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time
time_zonetexta zone name like 'Asia/Kathmandu', or an offset like '+05:45'

Example: UTC to the Nepal clock and back

SELECT to_timezone('2026-09-10T05:15:00Z', 'Asia/Kathmandu') AS nepal_clock,
       to_utc('2026-09-10T11:00:00Z', 'Asia/Kathmandu') AS utc,
       hour(to_timezone('2026-09-10T05:15:00Z', 'Asia/Kathmandu')) AS nepal_hour;

Result:

nepal_clock (TIMESTAMP)utc (TIMESTAMP)nepal_hour (LONG)
2026-09-10T11:00:00.000Z2026-09-10T05:15:00.000Z11

(1 row)

Example: A zone with summer time: London is +01:00 in September, +00:00 in January

SELECT to_timezone('2026-09-10T05:15:00Z', 'Europe/London') AS september, to_timezone('2026-01-10T05:15:00Z', 'Europe/London') AS january;

Result:

september (TIMESTAMP)january (TIMESTAMP)
2026-09-10T06:15:00.000Z2026-01-10T05:15:00.000Z

(1 row)

last_day

Syntax:

last_day(t)

The last day of the month of the UTC date: last_day('2026-02-10') is 2026-02-28. Accountants use it for the month-end date of a report (like Excel EOMONTH(date, 0)).

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time

Example

SELECT last_day('2026-02-10') AS feb, last_day('2028-02-10T10:00:00Z') AS leap_feb, last_day(CAST('2026-09-10' AS DATE)) AS sep,
       last_day(dateadd('month', 1, '2026-09-10')) AS next_month_end;

Result:

feb (DATE)leap_feb (DATE)sep (DATE)next_month_end (DATE)
2026-02-282028-02-292026-09-302026-10-31

(1 row)

Example: Month-end report date of every invoice (sample data: analysis-finance)

SELECT last_day(invoice_date) AS month_end, count(*) AS invoices, sum(amount) AS sales
FROM invoices
WHERE invoice_date >= '2026-01-01'
GROUP BY last_day(invoice_date)
ORDER BY month_end;

Result:

month_end (DATE)invoices (LONG)sales (DECIMAL(2))
2026-01-3111500.00
2026-03-31112000.00
2026-05-3114500.00
2026-07-31213500.00
2026-08-3114500.00
2026-09-30112000.00

(6 rows)

dateadd

Syntax:

dateadd(unit, amount, t)

Adds amount units to the time. A negative amount goes back. dateadd('d', 7, '2026-09-10') is one week later.

ArgumentTypeMeaning
unittext'y' (years), 'month' or 'mo' (months), 'w' (weeks), 'd' (days), 'h' (hours), 'm' (minutes), 's' (seconds), 'ms'. Long forms also work: 'year', 'months', 'week', 'day', 'hour', 'minute', ... (any case)
amountwhole numberhow many units; negative to go back
tTIMESTAMP, DATE, time text or millisecondsthe start time

Example

SELECT dateadd('d', 7, '2026-09-10T05:15:00Z') AS next_week, dateadd('month', 1, '2026-01-31') AS end_of_feb, dateadd('y', 1, CAST('2024-02-29' AS DATE)) AS leap_day_plus_year, dateadd('m', -90, '2026-09-10T05:15:00Z') AS minus_90_minutes, dateadd('h', 30, CAST('2026-09-10' AS DATE)) AS date_stays_date;

Result:

next_week (TIMESTAMP)end_of_feb (TIMESTAMP)leap_day_plus_year (DATE)minus_90_minutes (TIMESTAMP)date_stays_date (DATE)
2026-09-17T05:15:00.000Z2026-02-28T00:00:00.000Z2025-02-282026-09-10T03:45:00.000Z2026-09-11

(1 row)

Example: When does the 7-day free trial of each new user end? (sample data: fn-dates)

SELECT id, email, created_at, dateadd('d', 7, created_at) AS trial_ends
FROM signups
WHERE created_at >= '2026-09-03'
ORDER BY id;

Result:

id (INT)email (STRING)created_at (TIMESTAMP)trial_ends (TIMESTAMP)
6anita@hotmail.com2026-09-03T02:35:00.000Z2026-09-10T02:35:00.000Z
7suman@gmail.com2026-09-03T14:00:00.000Z2026-09-10T14:00:00.000Z
8maya@gmail.com2026-09-03T18:05:00.000Z2026-09-10T18:05:00.000Z
9kiran@gmail.com2026-09-04T04:25:00.000Z2026-09-11T04:25:00.000Z
10nabin@yahoo.com2026-09-06T06:15:00.000Z2026-09-13T06:15:00.000Z

(5 rows)

Example: The 10-year listing anniversary of each company (sample data: fn-dates)

SELECT symbol, listed_on, dateadd('y', 10, listed_on) AS ten_years
FROM listings
ORDER BY listed_on;

Result:

symbol (STRING)listed_on (DATE)ten_years (DATE)
CITY1986-01-011996-01-01
COAST1998-07-282008-07-28
TELCO2008-07-112018-07-11
ACME2015-05-082025-05-08
VOLT2019-08-282029-08-28

(5 rows)

Example: The amount must be a whole number (shows an error)

SELECT dateadd('d', 1.5, '2026-09-10');

Result:

Error: line 1, column 8: dateadd: the amount must be a whole number

datediff

Syntax:

datediff(unit, from, to)

How many whole units there are from from to to. datediff('d', '2026-09-01', '2026-09-10') is 9.

ArgumentTypeMeaning
unittext'y' (years), 'month' or 'mo' (months), 'w' (weeks), 'd' (days), 'h' (hours), 'm' (minutes), 's' (seconds), 'ms'; long forms like 'year', 'months', 'day', 'hours' also work
fromTIMESTAMP, DATE, time text or millisecondsthe start
toTIMESTAMP, DATE, time text or millisecondsthe end

Example

SELECT datediff('d', '2026-09-01', '2026-09-10') AS days, datediff('d', '2026-09-10', '2026-09-01') AS negative, datediff('h', '2026-09-10T00:00:00Z', '2026-09-10T05:59:00Z') AS hours_cut, datediff('m', '2026-09-10T11:00:00+05:45', '2026-09-10T15:00:00+05:45') AS market_minutes;

Result:

days (LONG)negative (LONG)hours_cut (LONG)market_minutes (LONG)
9-95240

(1 row)

Example: How long each company has been listed (up to 2026-09-11) (sample data: fn-dates)

SELECT symbol, listed_on,
       datediff('d', listed_on, '2026-09-11') AS days,
       datediff('w', listed_on, '2026-09-11') AS weeks,
       year('2026-09-11') - year(listed_on) AS calendar_years
FROM listings
ORDER BY listed_on;

Result:

symbol (STRING)listed_on (DATE)days (LONG)weeks (LONG)calendar_years (LONG)
CITY1986-01-0114863212340
COAST1998-07-2810272146728
TELCO2008-07-11663694818
ACME2015-05-08414459211
VOLT2019-08-2825713677

(5 rows)

Example: First and last day of the sample candles (sample data: sample)

SELECT min(time) AS first_day, max(time) AS last_day, datediff('d', min(time), max(time)) AS days_between
FROM ochl_day;

Result:

first_day (TIMESTAMP)last_day (TIMESTAMP)days_between (LONG)
2025-12-28T00:00:00.000Z2026-09-10T00:00:00.000Z256

(1 row)

Example: Whole months and years between two dates

SELECT datediff('month', '2026-01-01', '2026-09-10') AS months,
       datediff('month', '2026-01-10T10:00:00Z', '2026-02-10T09:00:00Z') AS one_hour_short,
       datediff('month', '2026-01-31', '2026-02-28') AS to_month_end,
       datediff('y', '2025-09-11', '2026-09-10') AS one_day_short,
       datediff('years', '1998-07-28', '2026-09-10') AS years;

Result:

months (LONG)one_hour_short (LONG)to_month_end (LONG)one_day_short (LONG)years (LONG)
801028

(1 row)

Example: Quarter is not a unit of datediff (shows an error)

SELECT datediff('quarter', '2026-01-01', '2026-09-10');

Result:

Error: line 1, column 8: datediff: unit must be y, month, w, d, h, m, s or ms

age

Syntax:

age(t)
age(to, from)

The time between two times, written like a person says it: '28 years 1 mon 13 days'. With one argument it is the time from t to today (today's UTC midnight), like PostgreSQL. Use it to show how old a company listing, an account or a user is.

ArgumentTypeMeaning
toTIMESTAMP, DATE, time text or millisecondsthe later time
fromTIMESTAMP, DATE, time text or millisecondsthe earlier time
tTIMESTAMP, DATE, time text or millisecondsone argument: the time to count from, up to today at 00:00 UTC

Example

SELECT age('2026-09-10', '1998-07-28') AS listed_age,
       age('2026-09-10T15:30:00Z', '2026-09-10T11:00:00Z') AS hours,
       age('2026-09-11', '2025-09-11') AS one_year,
       age('2026-03-01', '2026-01-31') AS month_and_day,
       age('2026-01-31', '2026-03-01') AS negative;

Result:

listed_age (STRING)hours (STRING)one_year (STRING)month_and_day (STRING)negative (STRING)
28 years 1 mon 13 days04:30:001 year1 mon 1 day-1 mons -1 days

(1 row)

Example: How long each company has been listed (up to 2026-09-11) (sample data: fn-dates)

SELECT symbol, listed_on, age('2026-09-11', listed_on) AS listed_for
FROM listings
ORDER BY listed_on;

Result:

symbol (STRING)listed_on (DATE)listed_for (STRING)
CITY1986-01-0140 years 8 mons 10 days
COAST1998-07-2828 years 1 mon 14 days
TELCO2008-07-1118 years 2 mons
ACME2015-05-0811 years 4 mons 3 days
VOLT2019-08-287 years 14 days

(5 rows)

Example: One argument: counted up to today's midnight (UTC)

SELECT age('2000-01-01') = age(date_trunc('day', now()), '2000-01-01') AS same;

Result:

same (BOOL)
true

(1 row)

make_date

Syntax:

make_date(year, month, day)

Builds a DATE from three numbers: make_date(2026, 9, 10) is 2026-09-10. Useful when a table keeps the year, month and day in separate columns, or to build the start of a fiscal year.

ArgumentTypeMeaning
yearwhole number-9999 to 9999
monthwhole number1 to 12
daywhole number1 to the last day of that month

Example

SELECT make_date(2026, 9, 10) AS d, make_date(2028, 2, 29) AS leap_day, make_date(year('2026-09-10'), 7, 17) AS fiscal_year_start;

Result:

d (DATE)leap_day (DATE)fiscal_year_start (DATE)
2026-09-102028-02-292026-07-17

(1 row)

Example: Invoices from the start of Nepal's fiscal year 2083/84 (sample data: analysis-finance)

SELECT id, invoice_date, customer, amount
FROM invoices
WHERE invoice_date >= make_date(2026, 7, 17)
ORDER BY invoice_date;

Result:

id (INT)invoice_date (TIMESTAMP)customer (STRING)amount (DECIMAL(2))
102026-07-20T00:00:00.000Zhari1500.00
112026-08-25T00:00:00.000Zgita4500.00
122026-09-10T00:00:00.000Zmaya12000.00

(3 rows)

Example: 30 February does not exist (shows an error)

SELECT make_date(2026, 2, 30);

Result:

Error: line 1, column 8: make_date: date 2026-2-30 does not exist

make_timestamp

Syntax:

make_timestamp(year, month, day, hour, minute, second)

Builds a TIMESTAMP from its parts. The parts are UTC. second may have a fraction: 30.5 is 30 seconds and 500 milliseconds.

ArgumentTypeMeaning
year, month, daywhole numbersthe date, as in make_date
hourwhole number0 to 23
minutewhole number0 to 59
secondnumber0 to less than 60, with a fraction for milliseconds

Example

SELECT make_timestamp(2026, 9, 10, 5, 15, 30.5) AS utc_time,
       make_timestamp(2026, 9, 10, 11, 0, 0) - 20700000 AS market_opens;

Result:

utc_time (TIMESTAMP)market_opens (TIMESTAMP)
2026-09-10T05:15:30.500Z2026-09-10T05:15:00.000Z

(1 row)

Example: Hour 24 is out of range (shows an error)

SELECT make_timestamp(2026, 9, 10, 24, 0, 0);

Result:

Error: line 1, column 8: make_timestamp: the time of day is out of range

to_char

Syntax:

to_char(t, format)
to_char(t, format, time_zone)

Writes a time as text in the format you want. to_char('2026-09-10T08:30:00Z', 'DD Mon YYYY') is 10 Sep 2026. With a time zone, the time is first moved to that zone: this is the easy way to show Nepal time. To write a number (to_char(1234.5, 'FM999,999.00')), see to_char for numbers.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe time
formattextthe pattern; the codes are in the table below
time_zonetextoptional: a zone name like 'Asia/Kathmandu', or an offset like '+05:45' or '-03:00'. Without it: UTC

Format codes (upper and lower case matter):

CodeMeaning2026-09-10 15:30:05.042 UTC gives
YYYYyear, 4 digits2026
YYlast 2 digits of the year26
MMmonth number, 2 digits09
Mon / MON / monshort month nameSep / SEP / sep
Month / MONTH / monthfull month nameSeptember / SEPTEMBER / september
DDday of the month, 2 digits10
DDDday of the year, 3 digits (001-366)253
Dy / DY / dyshort weekday nameThu / THU / thu
Day / DAY / dayfull weekday nameThursday / THURSDAY / thursday
Dweekday number, 1 = Sunday ... 7 = Saturday5
HH24hour 00-2315
HH12, HHhour 01-1203
MIminute, 2 digits30
SSsecond, 2 digits05
MSmillisecond, 3 digits042
AM, PMAM or PM (both codes give the right one)PM
am, pmam or pmpm
Qquarter of the year, 1-43
FMaccepted and ignored (names are never padded; numbers stay 2 digits)
"text"text in double quotes is copied as it is

Time zones: UTC, GMT, Z, Etc/UTC, Asia/Kathmandu, Asia/Katmandu, NPT, Asia/Kolkata, Asia/Calcutta, IST, Asia/Colombo, Asia/Dhaka, Asia/Thimphu, Asia/Karachi, Asia/Dubai, Asia/Bangkok, Asia/Jakarta, Asia/Shanghai, Asia/Hong_Kong, Asia/Singapore, Asia/Taipei, Asia/Tokyo, Asia/Seoul (any case), or an offset with a sign: '+05:45', '-03:00'.

Example

SELECT to_char('2026-09-10T15:30:05.042Z', 'YYYY-MM-DD HH24:MI:SS.MS') AS iso,
       to_char('2026-09-10T15:30:05.042Z', 'Dy, DD Mon YYYY HH12:MI AM') AS english,
       to_char('2026-09-10T15:30:05.042Z', 'DDD Q D') AS day_of_year_quarter_weekday,
       to_char(CAST('2026-09-10' AS DATE), 'DD/MM/YYYY') AS from_date;

Result:

iso (STRING)english (STRING)day_of_year_quarter_weekday (STRING)from_date (STRING)
2026-09-10 15:30:05.042Thu, 10 Sep 2026 03:30 PM253 3 510/09/2026

(1 row)

Example: Show a UTC time in Nepal time

SELECT to_char('2026-09-10T05:15:00Z', 'YYYY-MM-DD HH24:MI') AS utc,
       to_char('2026-09-10T05:15:00Z', 'YYYY-MM-DD HH24:MI', 'Asia/Kathmandu') AS nepal,
       to_char('2026-09-10T05:15:00Z', 'HH12:MI am', '+05:45') AS nepal_12h,
       to_char('2026-09-10T05:15:00Z', 'HH24:MI', 'Asia/Tokyo') AS tokyo;

Result:

utc (STRING)nepal (STRING)nepal_12h (STRING)tokyo (STRING)
2026-09-10 05:152026-09-10 11:0011:00 am14:15

(1 row)

Example: Last COAST trades of the day with the Nepal clock time (sample data: sample)

SELECT to_char(time, 'HH24:MI', 'Asia/Kathmandu') AS nepal_time, close, volume
FROM ochl_minutes
WHERE symbol = 'COAST' AND time IN '2026-09-10'
ORDER BY time DESC
LIMIT 3;

Result:

nepal_time (STRING)close (DOUBLE)volume (DOUBLE)
14:59376.11060
14:58376.21320
14:573761150

(3 rows)

Example: App sign-ups per Nepal date (sample data: fn-dates)

SELECT to_char(created_at, 'YYYY-MM-DD', 'Asia/Kathmandu') AS nepal_date, count(*) AS signups
FROM signups
GROUP BY to_char(created_at, 'YYYY-MM-DD', 'Asia/Kathmandu')
ORDER BY nepal_date;

Result:

nepal_date (STRING)signups (LONG)
2026-09-013
2026-09-022
2026-09-033
2026-09-041
2026-09-061

(5 rows)

Example: Month report with month names (sample data: sample)

SELECT to_char(time, 'YYYY-MM') AS sort_key, to_char(time, 'Mon YYYY') AS month,
       round(sum(close * volume) / 1000000, 2) AS turnover_millions
FROM ochl_day
WHERE symbol = 'VOLT'
GROUP BY to_char(time, 'YYYY-MM'), to_char(time, 'Mon YYYY')
ORDER BY sort_key;

Result:

sort_key (STRING)month (STRING)turnover_millions (DOUBLE)
2025-12Dec 202579.27
2026-08Aug 2026119.22
2026-09Sep 2026128.05

(3 rows)

Example: Words in the format: use double quotes

SELECT to_char('2026-09-10', 'Date: DD') AS wrong, to_char('2026-09-10', '"Date:" DD') AS right;

Result:

wrong (STRING)right (STRING)
5ate: 10Date: 10

(1 row)

Example: Zones with summer time are refused (shows an error)

SELECT to_char('2026-09-10T05:15:00Z', 'HH24:MI', 'Europe/London');

Result:

Error: line 1, column 8: to_char: time zone 'Europe/London' is not supported (it may change for daylight saving); use a fixed offset like '+05:45'

fiscal_year

Syntax:

fiscal_year(t)
fiscal_year(t, start_month)
fiscal_year(t, start_month, start_day)

The fiscal year (financial year) of a date, as the calendar year in which that fiscal year starts. A fiscal year is the 12-month year a company or a government uses for its accounts and taxes. It often does not start on 1 January: in Nepal it starts in mid-July, in India on 1 April.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe date
start_monthwhole numberthe month the fiscal year starts, 1-12; default 7 (July, Nepal)
start_daywhole numberthe day of that month it starts, 1-28; default 17 (see the notes)

Example

SELECT fiscal_year('2026-07-16') AS last_day_of_fy_2025, fiscal_year('2026-07-17') AS first_day_of_fy_2026,
       fiscal_year('2026-03-31', 4, 1) AS india_before_april, fiscal_year('2026-04-01', 4, 1) AS india_april,
       fiscal_year('2026-09-10', 1, 1) AS calendar_year;

Result:

last_day_of_fy_2025 (LONG)first_day_of_fy_2026 (LONG)india_before_april (LONG)india_april (LONG)calendar_year (LONG)
20252026202520262026

(1 row)

Example: Sales per fiscal year (Nepal start, 17 July) (sample data: analysis-finance)

SELECT fiscal_year(invoice_date) AS fiscal_year, count(*) AS invoices, sum(amount) AS sales
FROM invoices
GROUP BY fiscal_year(invoice_date)
ORDER BY fiscal_year;

Result:

fiscal_year (LONG)invoices (LONG)sales (DECIMAL(2))
2024213500.00
2025748000.00
2026318000.00

(3 rows)

Example: Day 29 or later cannot start a fiscal year (shows an error)

SELECT fiscal_year('2026-09-10', 1, 31);

Result:

Error: line 1, column 8: fiscal_year: the start month must be 1-12 and the start day 1-28

fiscal_quarter

Syntax:

fiscal_quarter(t)
fiscal_quarter(t, start_month)
fiscal_quarter(t, start_month, start_day)

The quarter inside the fiscal year, from 1 to 4. Each fiscal quarter is 3 months counted from the start day: with the Nepal start (17 July), quarter 1 is 17 July to 16 October, quarter 2 is 17 October to 16 January, and so on. Banks and listed companies in Nepal publish their quarterly reports by these quarters.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe date
start_monthwhole numberthe month the fiscal year starts, 1-12; default 7
start_daywhole numberthe day it starts, 1-28; default 17

Example

SELECT fiscal_quarter('2026-07-17') AS q1_start, fiscal_quarter('2026-10-16') AS q1_end, fiscal_quarter('2026-10-17') AS q2_start,
       fiscal_quarter('2027-07-16') AS q4_end, fiscal_quarter('2026-09-10', 4, 1) AS india, fiscal_quarter('2026-09-10', 1, 1) AS calendar;

Result:

q1_start (LONG)q1_end (LONG)q2_start (LONG)q4_end (LONG)india (LONG)calendar (LONG)
112423

(1 row)

Example: Quarterly sales report of the fiscal year (sample data: analysis-finance)

SELECT nepal_fiscal_year(invoice_date) AS fiscal_year, fiscal_quarter(invoice_date) AS quarter,
       count(*) AS invoices, sum(amount) AS sales
FROM invoices
GROUP BY nepal_fiscal_year(invoice_date), fiscal_quarter(invoice_date)
ORDER BY fiscal_year, quarter;

Result:

fiscal_year (STRING)quarter (LONG)invoices (LONG)sales (DECIMAL(2))
2081/824213500.00
2082/831213500.00
2082/83226000.00
2082/833112000.00
2082/834216500.00
2083/841318000.00

(6 rows)

nepal_fiscal_year

Syntax:

nepal_fiscal_year(t)

The name of Nepal's fiscal year of a date, as Nepal writes it in the Bikram Sambat (BS) calendar: '2083/84'. Nepal's fiscal year (arthik barsa) starts on Shrawan 1, which is about 16 or 17 July, and ends at the end of Ashadh the next year. Companies, banks and the tax office in Nepal use it for their reports.

ArgumentTypeMeaning
tTIMESTAMP, DATE, time text or millisecondsthe date

Example

SELECT nepal_fiscal_year('2026-07-16') AS before_shrawan, nepal_fiscal_year('2026-07-17') AS shrawan_1,
       nepal_fiscal_year('2026-09-10') AS today, nepal_fiscal_year(CAST('2000-01-01' AS DATE)) AS year_2000;

Result:

before_shrawan (STRING)shrawan_1 (STRING)today (STRING)year_2000 (STRING)
2082/832083/842083/842056/57

(1 row)

Example: Sales per Nepal fiscal year (sample data: analysis-finance)

SELECT nepal_fiscal_year(invoice_date) AS fiscal_year, min(invoice_date) AS first_invoice, max(invoice_date) AS last_invoice,
       count(*) AS invoices, sum(amount) AS sales
FROM invoices
GROUP BY nepal_fiscal_year(invoice_date)
ORDER BY fiscal_year;

Result:

fiscal_year (STRING)first_invoice (TIMESTAMP)last_invoice (TIMESTAMP)invoices (LONG)sales (DECIMAL(2))
2081/822025-06-20T00:00:00.000Z2025-07-16T00:00:00.000Z213500.00
2082/832025-07-17T00:00:00.000Z2026-07-10T00:00:00.000Z748000.00
2083/842026-07-20T00:00:00.000Z2026-09-10T00:00:00.000Z318000.00

(3 rows)

Example: Expenses of the accounting book per fiscal year (sample data: query-app)

SELECT nepal_fiscal_year(l.entry_date) AS fiscal_year, a.name AS expense, sum(l.debit) AS amount
FROM ledger l
JOIN accounts a ON a.code = l.account
WHERE a.type = 'expense'
GROUP BY nepal_fiscal_year(l.entry_date), a.name
ORDER BY fiscal_year, expense;

Result:

fiscal_year (STRING)expense (STRING)amount (DECIMAL(2))
2083/84Broker commission1030.00
2083/84Office rent25000.00

(2 rows)

Local time, for example Nepal

Syntax:

'2026-09-10T11:00:00+05:45'        -- write Nepal times with +05:45
to_timezone(time, 'Asia/Kathmandu')  -- the Nepal clock time (also time + 20700000)
to_char(time, format, 'Asia/Kathmandu')
time IN '2026-09-10' TIME ZONE 'Asia/Kathmandu'
date_trunc('day', time, 'Asia/Kathmandu')
SAMPLE BY 1h TIME ZONE 'Asia/Kathmandu'

KDB stores and shows every time in UTC. These tips use Nepal time as the example local zone: UTC + 5 hours 45 minutes, all year (Nepal has no summer time). For another zone change the offset and the milliseconds, for example -05:00 and - 18000000 for New York in winter. In a zone with summer time the fixed number is right for only part of the year.

TaskWrite
Put a Nepal time into KDB'2026-09-10T11:00:00+05:45' (without +05:45 the text is read as UTC)
Nepal hour, minute, day, weekdayhour(to_timezone(time, 'Asia/Kathmandu')), or add 20700000 ms: day_of_week(time + 20700000)
Show a time in Nepal timeto_char(time, 'YYYY-MM-DD HH24:MI', 'Asia/Kathmandu')
Rows of one Nepal dayWHERE time IN '2026-09-10' TIME ZONE 'Asia/Kathmandu' (see time IN)
Nepal midnight of a timedate_trunc('day', time, 'Asia/Kathmandu') or timestamp_floor('1d', time, 'Asia/Kathmandu')
Store daily bars at Nepal midnighta column time TIMESTAMP ROUND 1d TIME ZONE 'Asia/Kathmandu' (see TIME ZONE)
Candles by Nepal hours or daysSAMPLE BY 1h TIME ZONE 'Asia/Kathmandu' (see TIME ZONE)
QuestDB to_timezone(time, 'Asia/Kathmandu') (UTC to the local clock)the same: to_timezone
QuestDB to_utc(time, 'Asia/Kathmandu') (a local clock to UTC)the same: to_utc, or time AT TIME ZONE 'Asia/Kathmandu'

Example: QuestDB to_timezone and to_utc, and the older ways

SELECT to_timezone('2026-09-10T05:15:00Z', 'Asia/Kathmandu') AS to_timezone,
       CAST('2026-09-10T05:15:00Z' AS TIMESTAMP) + 20700000 AS plus_ms,
       to_utc('2026-09-10T11:00:00Z', 'Asia/Kathmandu') AS to_utc,
       CAST('2026-09-10T11:00:00Z' AS TIMESTAMP) AT TIME ZONE 'Asia/Kathmandu' AS at_time_zone;

Result:

to_timezone (TIMESTAMP)plus_ms (TIMESTAMP)to_utc (TIMESTAMP)at_time_zone (TIMESTAMP)
2026-09-10T11:00:00.000Z2026-09-10T11:00:00.000Z2026-09-10T05:15:00.000Z2026-09-10T05:15:00.000Z

(1 row)

Example: One market opening minute (11:00 in Nepal), three ways

SELECT CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) AS stored_utc,
       hour('2026-09-10T11:00:00+05:45') AS utc_hour,
       hour(CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) + 20700000) AS nepal_hour;

Result:

stored_utc (TIMESTAMP)utc_hour (LONG)nepal_hour (LONG)
2026-09-10T05:15:00.000Z511

(1 row)

Example: All minute candles of one Nepal trading day (sample data: sample)

SELECT count(*) AS candles, min(time) AS first_utc, max(time) AS last_utc
FROM ochl_minutes
WHERE symbol = 'CITY' AND time IN '2026-09-10' TIME ZONE 'Asia/Kathmandu';

Result:

candles (LONG)first_utc (TIMESTAMP)last_utc (TIMESTAMP)
2402026-09-10T05:15:00.000Z2026-09-10T09:14:00.000Z

(1 row)

Example: Hourly COAST candles on the Nepal clock (sample data: sample)

SELECT time, count(*) AS minutes, first(open) AS open, last(close) AS close
FROM ochl_minutes
WHERE symbol = 'COAST' AND time IN '2026-09-10'
SAMPLE BY 1h TIME ZONE 'Asia/Kathmandu';

Result:

time (TIMESTAMP)minutes (LONG)open (DOUBLE)close (DOUBLE)
2026-09-10T05:15:00.000Z60380.1381.3
2026-09-10T06:15:00.000Z56381.3378.4
2026-09-10T07:15:00.000Z60378.4376.4
2026-09-10T08:15:00.000Z60376.4376.1

(4 rows)

current_date

Syntax:

current_date
current_date()

Today's date on the session's clock (UTC unless SET TIME ZONE names a zone). The PostgreSQL name; KDB gives the same as CAST(now() AS DATE).

Example: Save the day a user logged in

Setup:

CREATE TABLE user_logins (user_id INT PRIMARY KEY, login_day DATE DEFAULT current_date);
INSERT INTO user_logins (user_id) VALUES (7);
SELECT user_id, login_day = current_date AS logged_in_today FROM user_logins;

Result:

user_id (INT)logged_in_today (BOOL)
7true

(1 row)

Example: Today in UTC and on the Nepal clock

SELECT current_date AS utc_day,
       CAST(now() + 20700000 AS DATE) AS nepal_day,
       current_date = CAST(now() AS DATE) AS same_as_now;

Result:

utc_day (DATE)nepal_day (DATE)same_as_now (BOOL)
2026-10-222026-10-22true

(1 row)

current_time, localtime

Syntax:

current_time
current_time()
localtime
localtime()

The clock time of day now, on the session's clock (UTC unless set), as text: HH:MM:SS.mmm. localtime is the same function.

Example: Is the market session open right now (Nepal clock)?

SELECT current_time AS utc_time_of_day,
       to_str(now() + 20700000, 'HH:mm') AS nepal_clock,
       localtime = current_time AS localtime_is_the_same;

Result:

utc_time_of_day (STRING)nepal_clock (STRING)localtime_is_the_same (BOOL)
05:43:50.53311:28true

(1 row)

localtimestamp

Syntax:

localtimestamp
localtimestamp()
localtimestamp(digits)

The time now on the session's clock, the PostgreSQL name for a time without a zone. In a UTC session it is the same as now(); after SET TIME ZONE 'Asia/Kathmandu' it is 5 h 45 min later (the Nepal wall clock, still shown with Z).

ArgumentTypeMeaning
digitsINThow many digits after the second PostgreSQL would keep; KDB always keeps milliseconds, so it changes nothing

Example

SELECT localtimestamp = now() AS same_as_now, year(localtimestamp) >= 2026 AS year_ok;

Result:

same_as_now (BOOL)year_ok (BOOL)
truetrue

(1 row)

transaction_timestamp, statement_timestamp, clock_timestamp

Syntax:

transaction_timestamp()
statement_timestamp()
clock_timestamp()

Three PostgreSQL names for the time now. In PostgreSQL they differ (start of the transaction, start of the statement, the clock right now). KDB gives the same time for all three: the time the statement started.

Example: All three are the time this statement started

SELECT transaction_timestamp() = statement_timestamp() AS same_1,
       statement_timestamp() = clock_timestamp() AS same_2,
       clock_timestamp() = now() AS same_as_now;

Result:

same_1 (BOOL)same_2 (BOOL)same_as_now (BOOL)
truetruetrue

(1 row)

make_interval

Syntax:

make_interval(years, months, weeks, days, hours, minutes, seconds)

Builds an interval (a length of time) from numbers. Every argument may be left out from the right; what is left out is 0.

ArgumentTypeMeaning
yearsnumberyears (12 months each)
monthsnumbermonths
weeksnumberweeks (7 days each)
daysnumberdays
hoursnumberhours
minutesnumberminutes
secondsnumberseconds

Example: The candle 15 minutes after each market minute (sample data: sample)

SELECT time, time + make_interval(0, 0, 0, 0, 0, 15, 0) AS fifteen_minutes_later
FROM ochl_minutes
WHERE symbol = 'CITY'
ORDER BY time
LIMIT 3;

Result:

time (TIMESTAMP)fifteen_minutes_later (TIMESTAMP)
2026-09-09T05:15:00.000Z2026-09-09T05:30:00.000Z
2026-09-09T05:16:00.000Z2026-09-09T05:31:00.000Z
2026-09-09T05:17:00.000Z2026-09-09T05:32:00.000Z

(3 rows)

Example: Years, months, weeks and a fraction

SELECT make_interval(1, 2, 0, 3) AS year_month_day,
       make_interval(0, 0, 2) AS two_weeks,
       make_interval(0, 0, 0, 0, 1, 30) AS ninety_minutes,
       make_interval(0, 0.5) AS half_a_month;

Result:

year_month_day (INTERVAL)two_weeks (INTERVAL)ninety_minutes (INTERVAL)half_a_month (INTERVAL)
1 year 2 mons 3 days14 days01:30:0015 days

(1 row)

justify_days, justify_hours, justify_interval

Syntax:

justify_days(interval)
justify_hours(interval)
justify_interval(interval)

Write an interval in bigger units: justify_days turns every 30 days into a month, justify_hours turns every 24 hours into a day, and justify_interval does both and also makes the signs agree.

ArgumentTypeMeaning
intervalINTERVALthe length of time to tidy up

Example: 45 days and 50 hours, written for a reader

SELECT justify_days(INTERVAL '45 days') AS in_months,
       justify_hours(INTERVAL '50 hours') AS in_days,
       justify_interval(INTERVAL '45 days 50 hours') AS both;

Result:

in_months (INTERVAL)in_days (INTERVAL)both (INTERVAL)
1 mon 15 days2 days 02:00:001 mon 17 days 02:00:00

(1 row)

Example: How long a dividend book closure lasted

SELECT justify_interval(make_interval(0, 0, 0, 40, 30)) AS book_closure_length;

Result:

book_closure_length (INTERVAL)
1 mon 11 days 06:00:00

(1 row)