postgresql date types - ghdrako/doc_snipets GitHub Wiki
-
https://www.postgresql.org/docs/current/datatype-datetime.html
-
https://www.postgresql.org/docs/current/functions-datetime.html
-
https://tapoueh.org/blog/2018/04/postgresql-data-types-date-timestamp-and-time-zones/
-
https://www.postgresql.org/docs/current/view-pg-settings.html.
show timezone;
Current
CURRENT_TIMESTAMP,transaction_timestamp(),now()- functions all return values based on the start time of the current transactionstatement_timestamp()returns the start time of the current statement (more specifically, the time of receipt of the latest command message from the client)CURRENT_DATEeqivalent ofCURRENT_TIMESTAMP::DATEcurrent_timeclock_timestamp()returns the actual current time, and therefore its value changes even within a single SQL command
Note: statement_timestamp() is STABLE just like all variants of now(). (They always return the same value within the same SQL command). But clock_timestamp() necessarily is only VOLATILE. The difference may be significant.
Convert timestamp to date prevent using index
| Wrong | good |
|---|---|
| scheduled_departure ::date BETWEEN '2023-08-17' AND '2023-08-18' | scheduled_departure >='2023-08-17' AND scheduled_departure <'2023-08-19' |
| update_ts::date=CURRENT_DATE | update_ts>= CURRENT_DATE AND update_ts< CURRENT_DATE +1 |
| coalesce(actual_departure, scheduled_departure) BETWEEN '2023-08-17' AND '2023-08-18' | (actual_departure BETWEEN '2023-08-17' AND '2023-08-18') OR (actual_departure IS NULL AND scheduled_departure BETWEEN '2023-08-17' AND '2023-08-18') |
Decorated literal - standard SQL - przenosne
we decorate the literal with its data type so that PostgreSQL doesn’t have to guess what it is.
select date '2010-02-20';
select timestamp '2024-10-01 00:00:00';
select time '13:12:10';
Cast - postgresql only
select '2010-02-20'::date;
select '2024-10-01 00:00:00'::timestamp;
select '13:12:10'::time;
cast
select cast('2010-02-20' as date);
select cast('2024-10-01 00:00:00' as timestamp);
select cast('13:12:10' as time);
Overlaps operator
- https://hakibenita.com/postgresql-unknown-features#find-overlapping-ranges
- https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-TABLE
(start1, end1) OVERLAPS (start2, end2)
(start1, length1) OVERLAPS (start2, length2)
This expression yields true when two time periods (defined by their endpoints) overlap, false when they do not overlap. The endpoints can be specified as pairs of dates, times, or time stamps; or as a date, time, or time stamp followed by an interval. When a pair of values is provided, either the start or the end can be written first; OVERLAPS automatically takes the earlier value of the pair as the start. Each time period is considered to represent the half-open interval start <= time < end, unless start and end are equal in which case it represents that single time instant. This means for instance that two time periods with only an endpoint in common do not overlap.
SELECT (DATE '2001-02-16', DATE '2001-12-21') OVERLAPS
(DATE '2001-10-30', DATE '2002-10-30');
Result: true
SELECT (DATE '2001-02-16', INTERVAL '100 days') OVERLAPS
(DATE '2001-10-30', DATE '2002-10-30');
Result: false
SELECT (DATE '2001-10-29', DATE '2001-10-30') OVERLAPS
(DATE '2001-10-30', DATE '2001-10-31');
Result: false
SELECT (DATE '2001-10-30', DATE '2001-10-30') OVERLAPS
(DATE '2001-10-30', DATE '2001-10-31');
Result: true
new_meetings AS (
SELECT
id,
starts_at::timestamptz as starts_at,
ends_at::timestamptz as ends_at
FROM (VALUES
('A', '2021-10-01 11:10 UTC', '2021-10-01 11:55 UTC'),
('B', '2021-10-01 11:20 UTC', '2021-10-01 12:05 UTC'),
('C', '2021-10-01 11:20 UTC', '2021-10-01 11:55 UTC'),
('D', '2021-10-01 11:10 UTC', '2021-10-01 12:05 UTC'),
('E', '2021-10-01 11:15 UTC', '2021-10-01 12:00 UTC'),
('F', '2021-10-01 12:00 UTC', '2021-10-01 12:10 UTC'),
('G', '2021-10-01 11:00 UTC', '2021-10-01 11:15 UTC')
) as t(
id, starts_at, ends_at
)
)
SELECT
*
FROM
meetings, new_meetings
WHERE
(new_meetings.starts_at, new_meetings.ends_at)
OVERLAPS (meetings.starts_at, meetings.ends_at);
starts_at │ ends_at │ id │ starts_at │ ends_at
─────────────────────┼─────────────────────┼────┼─────────────────────┼────────────────────
2021-10-01 11:15:00 │ 2021-10-01 12:00:00 │ A │ 2021-10-01 11:10:00 │ 2021-10-01 11:55:00
2021-10-01 11:15:00 │ 2021-10-01 12:00:00 │ B │ 2021-10-01 11:20:00 │ 2021-10-01 12:05:00
2021-10-01 11:15:00 │ 2021-10-01 12:00:00 │ C │ 2021-10-01 11:20:00 │ 2021-10-01 11:55:00
2021-10-01 11:15:00 │ 2021-10-01 12:00:00 │ D │ 2021-10-01 11:10:00 │ 2021-10-01 12:05:00
2021-10-01 11:15:00 │ 2021-10-01 12:00:00 │ E │ 2021-10-01 11:15:00 │ 2021-10-01 12:00:00
Convert timestamp to date
select DATE(CURRENT_TIMESTAMP);
select CURRENT_TIMESTAMP::date;
Extract from date
- https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
- https://www.postgresql.org/docs/current/functions-formatting.html
select date::date,
extract('isodow' from date) as dow,
to_char(date, 'dy') as day,
extract('isoyear' from date) as "iso year",
extract('week' from date) as week,
extract('day' from
(date + interval '2 month - 1 day')
)
as feb,
extract('year' from date) as year,
extract('day' from
(date + interval '2 month - 1 day')
) = 29
as leap
from generate_series(date '2000-01-01',
date '2010-01-01',
interval '1 year')
as t(date);
date │ dow │ day │ iso year │ week │ feb │ year │ leap
2000-01-01 │ 6 │ sat │ 1999 │ 52 │ 29 │ 2000 │ t
2001-01-01 │ 1 │ mon │ 2001 │ 1 │ 28 │ 2001 │ f
2002-01-01 │ 2 │ tue │ 2002 │ 1 │ 28 │ 2002 │ f
2003-01-01 │ 3 │ wed │ 2003 │ 1 │ 28 │ 2003 │ f
2004-01-01 │ 4 │ thu │ 2004 │ 1 │ 29 │ 2004 │ t
2005-01-01 │ 6 │ sat │ 2004 │ 53 │ 28 │ 2005 │ f
2006-01-01 │ 7 │ sun │ 2005 │ 52 │ 28 │ 2006 │ f
2007-01-01 │ 1 │ mon │ 2007 │ 1 │ 28 │ 2007 │ f
2008-01-01 │ 2 │ tue │ 2008 │ 1 │ 29 │ 2008 │ t
2009-01-01 │ 4 │ thu │ 2009 │ 1 │ 28 │ 2009 │ f
2010-01-01 │ 5 │ fri │ 2009 │ 53 │ 28 │ 2010 │ f
(11 rows) It
By definition, ISO weeks start on Mondays and the ??rst week of a year contains January 4 of that year. In other words, the first Thurs-day of a year is in week 1 of that year.
\set beginning '2017-04-01'
\set months 3
Select name
From race
where date >= date :'beginning'
and date < date :'beginning'
+ :months * interval '1 month';
Funkcje
| Funkcja | Opis |
|---|---|
AGE(X,Y) |
Zwraca różnicę między datami (X-Y) w postaci przedziału w latach, miesiącach, dniach, godzinach itp. AGE('2023-03-08', '2011-06-14') — 11 lat 8 miesięcy 24 dni |
AGE([timestamp ]X) |
Zwraca różnicę między bieżącą datą a datą X w postaci odstępu w latach, miesiącach, dniach, godzinach itd. AGE( timestamp '2023-03-08') —1 mon 17 days |
CURRENT_DATE |
Zwraca bieżącą datę |
CURRENT_TIME |
Zwraca aktualną porę dnia wraz z informacją o strefie czasowej CURRENT_TIME - 13:43:14 +0300 |
CURRENT_TIMESTAMP |
Zwraca bieżącą datę i godzinę wraz z informacją o strefie czasowej CURRENT_TIMESTAMP - 25-04-2023 13:49:30.057 +0300 |
NOW () |
Zwraca bieżącą datę i godzinę wraz z informacją o strefie czasowej NOW() - 26-04-2023 14:03:04.695 +0300 |
DATE_TRUNC(M,X) |
Przycina wartość X do określonej precyzji M (second; minute; hour; day; dow; month; year) SELECT CURRENT_DATE, DATE_TRUNC('MONTH', CURRENT_DATE) - 25-04-2023101-04-2023 00:00:00.000 +0300 |
EXTRACT(M FROM X) |
Wyodrębnia określoną część M (second; minute; hour; day; dow; month; year) z wartości X SELECT CURRENT_DATE, EXTRACT('MONTH' FROM CURRENT_DATE) - 25-04-20231 4 |
JUSTIFY_INTERVAL(INTERVAL) |
Konwertuje wartość interval na prawidłowy format daty i czasu TIMESTAMP SELECT JUSTIFY_INTERVAL(INTERVAL'5000 hour 15 minute') — 6 mens 28 days 08:15:00 |
Standard ISO 8601 zaleca używanie formatu 'yyyy-mm-dd' (rok-miesiąc-dzień) do wyświetlania danych typu date, ale PostgreSQL pozwala również używać innych formatów.
Wartości mające typy daty i czasu mogą uczestniczyć w operacjach arytmetycznych, ale z pewnymi ograniczeniami. Na przykład różnica między dwoma datami równa się liczbie dni, które upłynęły między tymi datami, ale nie można bezpośrednio dodawać wartości mających typ Date.
Dodanie całkowitej wartości n do wartości typu Date jest równoważne dodaniu n dni do daty.
SELECT '05-4-2023'::DATE + 45 as nev_date;
nev_date
I----------- +
20-05-20231
Wyciagnieniec dnia
- EXTRACT(DAY FROM ...) → zwraca INTEGER (np. 11)
- DATE_PART('day', ...) → zwraca FLOAT (11.0)
- TO_CHAR(..., 'DD') → zwraca TEXT ('11' lub '01' dla pojedynczych cyfr)
Java jdbc exeute analyze
final Statement st2 = connection.createStatement();
st2.executeUpdate("VACUUM FULL ANALYZE VERBOSE");
st2.close();
show DateStyle;
select * from pg_settings where name ='DateStyle';
name | DateStyle
setting | ISO, MDY
[..]
sourcefile |
sourceline |
pending_restart | f
Using the pg_settings view, we
can view the parameters set in the postgresql.conf configuration file. In the preceding
result, we can see that the configuration for displaying the date is MDY (month/day/year).
If we want to change this parameter globally, we have to edit the postgresql.conf file.
set DateStyle='ISO MDY' ;
select '12-31-2020'::date;
date
------------
2020-12-31
select to_date('31/12/2020','dd/mm/yyyy') ;
to_date
------------
2020-12-31
create table new_posts as select pk,title,created_on::timestamp
with time zone as created_on_t, created_on::timestamp without time zone as
create_on_nt from posts;
extract(y From current_date) as year
date_trunc('datepart', field) -
datepart: millennium,century,decade,year,quarter,month,week,day,hour,minute,second,milliseconds,microseconds
SQL>select date_truncate('month',DATE '2025-04-17');
2025-04-01 00:00:00.000
SQL>select date_truncate('year',DATE '2025-04-17');
2025-01-01 00:00:00.000
SQL>select date_truncate('hour',TIMESTAMP '2025-04-17 14:25:23');
2025-04-17 14:00:00.000
DATE_TRUNC('month', now())
SELECT DATE_TRUNC('hour', TIMESTAMP '2017-03-17 02:09:30');
SELECT date_trunc('minute', TIMESTAMP '2017-03-17 02:09:30');
SELECT
date_trunc('month', rental_date) m,
COUNT (rental_id)
FROM
rental
GROUP BY
m
ORDER BY
m;
SELECT
date_trunc('month', order_date) AS month,
COUNT(*) AS total_orders,
SUM(total_amount) AS monthly_total
FROM
orders
GROUP BY
date_trunc('month', order_date)
ORDER BY
month;
Convert to char
select to_date(20230219',YYYYMMDD');
select to_timestamp('28 Oct 2020 09:36:47 am','DD Mon YYYY HH:MI:SS AM');
select to_char(clock_change_date, 'Mon DD, YYYY') from clock_change;
SELECT TO_CHAR('2016-08-12 16:40:32'::TIMESTAMP, 'DD Mon YYYY HH:MI:SSPM');
SELECT TO_CHAR('2016-08-12 16:40:32'::TIMESTAMP,'"Today is "FMDay", the "DDth" day of the month of "FMMonth" of "YYYY');
SELECT TO_CHAR('2016-08-12 16:40:32'::TIMESTAMP, 'TMDay, DD" de "TMMonth" del año "YYYY'); -- TM (translation mode) modifier
--This option uses the localization setting of the server running PostgreSQL or the client connecting to it.
last day of month
SELECT (DATE_TRUNC('MONTH', ('201608'||'01')::DATE) + INTERVAL '1 MONTH - 1 day')::DATE;
TIMESTAMP and TIMESTAMPTZ
PostgreSQL provides you with two temporal data types for handling timestamp:
- timestamp: a timestamp without timezone one.
- timestamptz: timestamp with a timezone.
timestamptz nie jest pełnoprawnym „timestamp with time zone” tak jak w oracle i nie nadaje się do przyszłych dat, jeśli potrzebujesz zachować reguły strefowe. Trzeba dodatkowej kolumny na strefę. Utrata strefy przy zapisie powoduje ze timestamptz nie nadaje się do przechowywania „planowanych lokalnych czasów”
timestamp without time zone ma dokładnie ten sam format binarny jak timestampz. Roznica jest przy parserze wejsciowym i wyjsciowym.
- przy zapisie: Jeśli podasz
2025-03-01 00:00:00 America/New_York, Postgres weźmie reguły strefy (tzdata), przeliczy ten moment na "mikrosekundy od epoki UTC" i zapisze wynik. Oryginalna informacja o nazwie strefy i jej regułach zostaje utracona. - przy odczycie: Przy SELECT Postgres używa TimeZone sesji, by wyświetlić z powrotem w lokalnym czasie (chyba że użyjesz AT TIME ZONE). Zawsze można „sformatować” wartość na inną strefę, bo wewnętrznie to instant.
PostgreSQL stores the timestamptz in UTC value.
- When you insert a value into a timestamptz column, PostgreSQL converts the timestamptz value into a UTC value and stores the UTC value in the table.
- When you query timestamptz from the database, PostgreSQL converts the UTC value back to the time value of the timezone set by the database server, the user, or the current database connection.
SELECT
pg_column_size('2000-01-01 00:00:00 +00:00'::timestamp) as "timestamp byte size",
pg_column_size('2000-01-01 00:00:00 +00:00'::timestamptz) as "timestamptz byte size";
+--------------------+-----------------------+
|timestamp byte size | timestamptz byte size |
+--------------------+-----------------------+
| 8 | 8 |
+--------------------+-----------------------+
select pg_column_size(timestamp without time zone 'now'),
pg_column_size(timestamp with time zone 'now');
PostgreSQL doesn’t store the time zone they come from with your timestamp.
For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system’s TimeZone parameter, and is converted to UTC using the offset for the timezone zone.
CREATE TABLE timestamp_demo (
ts TIMESTAMP,
tstz TIMESTAMPTZ
);
SET timezone = 'America/Los_Angeles';
SHOW TIMEZONE;
INSERT INTO timestamp_demo (ts, tstz)
VALUES('2016-06-22 19:10:25-07','2016-06-22 19:10:25-07');
SELECT
ts, tstz
FROM
timestamp_demo;
ts | tstz
---------------------+------------------------
2016-06-22 19:10:25 | 2016-06-22 19:10:25-07
(1 row)
SET timezone = 'America/New_York';
SELECT
ts,
tstz
FROM
timestamp_demo;
Code language: SQL (Structured Query Language) (sql)
ts | tstz
---------------------+------------------------
2016-06-22 19:10:25 | 2016-06-22 22:10:25-04
(1 row)
SELECT NOW();
now() function always returns the same timestamp within a single transaction. If you want to see the clock running while in a transaction, use the clock_timestamp() function instead.
SELECT CURRENT_TIMESTAMP;
SELECT TIMEOFDAY();
timeofday
-------------------------------------
Wed Jun 22 20:51:12.632420 2016 PDT
SHOW TIMEZONE;
Code language: SQL (Structured Query Language) (sql)
TimeZone
---------------------
America/Los_Angeles
(1 row)
-- To convert 2016-06-01 00:00 to America/New_York timezone
SELECT timezone('America/New_York','2016-06-01 00:00');
Code language: SQL (Structured Query Language) (sql)
timezone
---------------------
2016-06-01 03:00:00
-- Note that we pass the timestamp as a string to the timezone() function, PostgreSQL casts it to timestamptz implicitly. It is better to -- cast a timestamp value to the timestamptz data type explicitly as the following statement:
SELECT timezone('America/New_York','2016-06-01 00:00'::timestamptz);
SET TIME ZONE ‘UTC+3’;
SELECT '2000-09-15 19:00+11:00'::TIMESTAMP, '2000-09-15 19:00+11:00'::TIMESTAMPTZ;
SELECT ‘2019-07-14 17:00:00.545454’::TIMESTAMP(0); – rounded up
select timestamptz '2017-01-08 04:05:06', -- handled by the timezone session parameter
timestamptz '2017-01-08 04:05:06+02'; -- input the time zone in the timestamp values directly
--- convert the stored timestamp to the client’s timezone at the database layer
SELECT '2000-01-01 00:00:00 +00:00'::timestamptz at time zone 'Europe/Rome' as "Rome's timestamp";
CURRENT_TIMESTAMP(precision)
If you omit the precision argument, the CURRENT_TIMESTAMP() function will return a TIMESTAMP with a time zone that includes the full fractional seconds precision available.
The CURRENT_TIMESTAMP() function returns a TIMESTAMP WITH TIME ZONE that represents the date and time at which the transaction started.Internally, the CURRENT_TIMESTAMP() is implemented with the NOW() function
CREATE TABLE note(
note_id serial PRIMARY KEY,
message varchar(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
TRANSACTION_TIMESTAMP() function is equivalent to the CURRENT_TIMESTAMP function.
TIME and TIMETZ
TIMEis still encoded with 8 bytes, representing microseconds since midnight.TIMETZis encoded with 12 bytes, with 8 bytes representing microseconds since midnight and 4 bytes for storing the time zone offset in seconds west of UTC
CURRENT_TIME
select ‘10:00’::time + ‘14 hours’::interval;
select ‘17:00:00.545454’::time(0), ‘17:00:00.545454+03’::timetz(0); -- parsing
Time Intervals
An interval describes a duration, like a month or two weeks, or even a millisecond:
Interval can be specify in two wys
INERVALkeyward
SELECT SUM(total_amount)
FROM orders
WHERE order_date >= NOW() - INTERVAL '90 days';
SELECT SUM(total_amount)
FROM orders
WHERE order_date BETWEEN (NOW() - INTERVAL '90 days') AND (NOW() - INTERVAL '30 days')
- as a cast
SELECT SUM(total_amount)
FROM orders
WHERE order_date >= NOW() - '90 days'::interval;
SELECT 10*INTERVAL'5 hour 15 minute' as new_time;
new_time I
---------+
52:30:001
SELECT JUSTIFY_INTERVAL(1O*INTERVAL'O day 5 hour 15 minute') as new time;
new time I
---------------+
2 days 04:30:001
SELECT JUSTIFY_INTERVAL(INTERVAL'5000 hour 15 minute') as new_date
new I
-----------------------+
6 mens 28 days 08:15:001
Używając funkcji `EXTRACT()`, można wyodrębnić określone pole z wartości mającej typ INTERVAL.
SELECT EXTRACT(day FROM JUSTIFY_INTERVAL(INTERVAL'5000 hour 15 minute')) as days; days I -----+ 28
SELECT employee_id,hire_date, CURRENT_DATE, (CURRENT_DATE - hire_date) AS days, AGE(hire_date) FROM Employees WHERE employee_id=145 employee_id | hire_date |current_date | days | age ------------ |------------|-------------- |----- | --------------------------------------+ 145| 01-10-1996| 26-04-2023| 97031| 26 years 6 mens 25 days I
Wynik, który zwraca funkcja AGE(), ma typ INTERVAL. Używając funkcji EXTRACT, można wybrać i wykorzystać określoną część tego wyniku
SELECT employee_id, first_name, last_name, hire_date, AGE(hire_date) FROM Employees WHERE EXTRACT(year FROM AGE(hire_date))>30;
SELECT employee_id, salary*(EXTRACT(YEAR FROM AGE(hire_date))*12 + EXTRACT(MONTH FROM AGE(hire_date)))as sum_salary FROM Employees WHERE department_id = 30 ORDER BY sum_salary DESC
set intervalstyle to postgres;
select interval '1 month',
interval '2 weeks',
2 * interval '1 week',
78389 * interval '1 ms';
interval │ interval │ ?column? │ ?column?
══════════╪══════════╪══════════╪══════════════
1 mon │ 14 days │ 14 days │ 00:01:18.389
(1 row)
set intervalstyle to postgres_verbose;
select interval '1 month',
interval '2 weeks',
2 * interval '1 week',
78389 * interval '1 ms';
interval │ interval │ ?column? │ ?column?
══════════╪═══════════╪═══════════╪═════════════════════
@ 1 mon │ @ 14 days │ @ 14 days │ @ 1 min 18.389 secs
(1 row)
select d::date as month,
(d + interval '1 month' - interval '1 day')::date as month_end,
(d + interval '1 month')::date as next_month,
(d + interval '1 month')::date - d::date as days
from generate_series(
date '2017-01-01',
date '2017-12-01',
interval '1 month'
)
as t(d);
When you attach an interval to a date or timestamp in PostgreSQL then the number of days in that interval adjusts to the specific calendar entry you’ve picked. Otherwise, an interval of a month is considered to be 30 days.
Interwal otrzymam jak odejmiemy dwa znaczniki czasowe od siebie
select '15:30:00'::time - '12:30:00'::time as inerwal_example, pg_typeof('15:30:00'::time - '12:30:00'::time)
03:00:00 interval
Select TIMESTAMP '2024-03-01 00:00:00' - TIMESTAMP '2024-02-01' as deys_in_febuaryn;
29 days
Odejmujac dwie daty otrzymamy liczbę dni
Select DATE '2024-03-01' - DATE '2024-02-01' as deys_in_febuaryn;
29
AGE()
AGE(timestamp,timestamp);
select age(date '2025-05-03',date '2024-05-03');
age
-----------------------
1 year
select age(timestamp '2023-04-01 14:30:00',timestamp '2022-03-01 12:00:00');
age
-----------------------
1 year 1 mon 02:30
select age(date '2023-04-03',current_date');
age
-2 year -1 month
SELECT AGE('2017-01-01','2011-06-24');
age
-----------------------
5 years 6 mons 7 days
If you want to use the current date as the first argument, you can use the following form of the AGE() function:
AGE(timestamp); -- to samo co AGE(current_date,timestamp);
MAKE_DATE()
MAKE_DATE( year int, month int, day int ) → date
SELECT MAKE_DATE(2023,3, 25);
make_date
------------
2023-03-25
(1 row)
The MAKE_DATE() function automatically handles the leap years
SELECT MAKE_DATE(2024, 2, 29);
make_date
------------
2024-02-29
(1 row)
Generate sequential dates
SELECT MAKE_DATE(2023, 1, day) dates
FROM generate_series(1, 7) AS day;
MAKE_TIME()
MAKE_TIME ( hour int, min int, sec double precision ) → time
SELECT MAKE_TIME(22,30,45);
make_time
-----------
22:30:45
(1 row)
SELECT MAKE_TIME(25,30,45);
Error:
ERROR: time field value out of range: 25:30:45
Even though the type of hour and minute parameters are integers and seconds are double precision, you can pass string arguments to the MAKE_TIME() function.
SELECT MAKE_TIME('8', '30', '59.999999');
make_time
-----------------
08:30:59.999999
(1 row)