Postgres Concate: Date + Timestamp + Integer of 7 - postgresql

How can I combine these two columns and add integer of 7 to it? In postgres.
Both columns are in the table a_event.
start_time is a timestamp without time zone data type.
start_date is a date data type.
so far I have:
SELECT start_time || start_date AS start_date_time
FROM a_event;
This works but it shows:
2015-03-06 21:17:162015-02-06
How can I get it to simply show:
2015-03-06 13:17:16 with an added 7 days so: 2015-03-13 in the desired result.

The || operator concatenates two strings, so the 'start_time' and 'start_date' columns are converted to text and then concatenated to give the result you see.
You want to add 7 days to the starting date. That is simply:
SELECT start_date + 7 AS start_date_time
FROM a_event;
On a date data type the + operator adds a number of days.
If you want to keep the starting time information, the solution is slightly more complex:
SELECT start_time + interval '7 days' AS start_date_time
FROM a_event;
The timestamp data type records microseconds since 01-01-1970, so you have to explicitly indicate that you want to add an interval of 7 days (and not 7 microseconds).

Related

Create date column from year and doy column

Is there a way to create a date column combining one column having the year as string and one column containing a date-of-year (doy) as integer?
I am aware of methods like SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40'); or SELECT to_char(date_trunc('year', now()) + interval '169 days', 'MM/DD') but when trying to replace the "hard coded" stings with the columns I always get some kind of an error.
SELECT s.id, s.year, s.doy,
((s.year||'-01-01')::date + (s.doy||' days')::interval )::date AS date
FROM table_name AS s
the (s.year||'-01-01') or (s.doy||' days') concats the column value with a required string and the ::date or ::interval changes the resulting string type
You can use the make_date() function and add the number of days directly because date + integer is a valid operation:
select make_date(s.year, 1, 1) + s.doy as date
from ...

Calendar days since date in days

Given the following sqlfiddle: http://www.sqlfiddle.com/#!17/f483a/2/0
create table test (
start_date date
);
insert into test values ('2019/01/01');
select
start_date,
age(now()::date,start_date) as date_diff
from test;
Which generates the following output:
date_diff | 0 years 7 mons 27 days 0 hours 0 mins 0.00 secs
How could I instead generate the correct number of calendar days
239 days
without using a custom function?
Don't use the age function. Subtracting a date from a date yields an integer. now() returns a timestamp so you need to use current_date instead.
select start_date,
current_date - start_date as date_diff
from test;

How to cast an int of microseconds into a interval field in postgres?

There is this question about how to extract microseconds from an interval field
I want to do the opposite, I want to create an interval from a numeric microseconds. How would I do this?
The reason is I want to take a table of this format
column_name | data_type
-------------+--------------------------
id | bigint
date | date
duration | numeric
and import it into a table like this
column_name | data_type
-------------+--------------------------
id | integer
date | date
duration | interval
Currently I am trying:
select CAST(duration AS interval) from boboon.entries_entry;
which gives me:
ERROR: cannot cast type numeric to interval
LINE 1: select CAST(duration AS interval) from boboon.entries_entry;
You can do:
select duration * interval '1 microsecond'
This is how you convert any date part to an interval in Postgres. Postgres supports microseconds, as well as more common units.
you can append the units and then cast to interval
example:
select (123.1234 || ' seconds')::interval
outputs:
00:02:12.1234
valid units are the following (and their plural forms):
microsecond
millisecond
second
minute
hour
day
week
month
quarter
year
decade
century
millennium

Postgresql: How to find hours between 2 dates and 2 times?

Postgresql 9.1
I'm trying to use a query to find the difference, in fractional/decimal hours, between 2 dates and 2 times for a timesheet system. I'm using the query to make sure the software (not written by me) doesn't have any bugs. Here are the fields in the table I'm using: startdate is a Date field, starttime is a Time field, enddate is a Date field, endtime is a Time field.
I've looked at the date time docs for 9.1 and still haven't found what I need.
age() takes 2 timestamps and appears to give a difference in integer, not fractional, days. I don't think it's possible to multiply the result of age() by 24 to get hours. Nor do I know how to include the time in the age() function.
I could not find out to convert a date and time to some thing else to use another function.
I have searched Google and Stackoverflow and have not found info to help me. I've been spending about 4 weeks on this off and on. So probably 30 hours already.
NOTE: I don't think I can add user-defined functions. I don't have the permissions.
Example data:
Startdate and time: '2016-04-29' and '23:00:00'
Enddate and time: '2016-04-30' and '01:30:00'
I've also tried this sql statement.
SELECT employeetime.dcmasterid as empid,
nonchargeabletime.startdate as ncsdate,
nonchargeabletime.starttime as ncstime,
nonchargeabletime.enddate as ncedate,
nonchargeabletime.endtime as ncetime,
employeetime.dchours as normhrs,
(timestamp (startdate || ' ' || starttime) - timestamp (enddate || ' ' || endtime)) as diffhrs
FROM employeetime, nonchargeabletime
WHERE (nonchargeabletime.employeetime=employeetime.dcautoinc)
AND (nonchargeabletime.startdate >= '2016-04-24')
AND (nonchargeabletime.startdate <= '2016-04-30')
AND (employeetime.dcmasterid IN ('BLURG'))
AND (nonchargeabletime.nonchargeabletype=10)
ORDER BY employeetime.dcmasterid, nonchargeabletime.startdate, nonchargeabletime.starttime;
But I get a syntax error at startdate where it says (timestamp (startdate ||.
Anyone have any clues how to do this?
Thank you.
Adding a time to a date yields a timestamp and subtracting one timestamp from another returns an interval.
So all you need to do is:
(enddate + endtime) - (startdate + starttime) as diff
An interval is nice in the context of SQL, but usually harder to handle in a programming language. You can easily convert an interval to seconds using extract(epoch from interval)
If you want to convert that to hours use extract and divide by 3600
extract(epoch from (enddate + endtime) - (startdate + starttime))/3600 as diff_hours
Since you don't have strings, you can't use || operator, but you can just add time to date (http://www.postgresql.org/docs/9.1/static/functions-datetime.html).
This should work (you can floor result if you want integer hours):
postgres=# create temporary table ts (startdate date, starttime time, enddate date, endtime time);
CREATE TABLE
postgres=# insert into ts values('2016-05-03', '11:45:15', '2016-05-04', '13:55:43');
INSERT 0 1
postgres=# SELECT startdate,starttime,enddate,endtime, (enddate+endtime)-(startdate+starttime) as interval from ts;
startdate | starttime | enddate | endtime | interval
------------+-----------+------------+----------+----------------
2016-05-03 | 11:45:15 | 2016-05-04 | 13:55:43 | 1 day 02:10:28
(1 row)
postgres=# SELECT startdate,starttime,enddate,endtime, EXTRACT(epoch FROM ((enddate+endtime)-(startdate+starttime)))/3600 as hours from ts;
startdate | starttime | enddate | endtime | hours
------------+-----------+------------+----------+------------------
2016-05-03 | 11:45:15 | 2016-05-04 | 13:55:43 | 26.1744444444444
(1 row)
WITH zooi(startdate,starttime, enddate,endtime) AS (
VALUES('2016-04-29'::date , '23:00:00'::time
,'2016-04-30'::date , '01:30:00'::time )
)
, stamps (sta, sto) AS (
select (z.startdate+z.starttime)::timestamp
, (z.enddate+z.endtime)::timestamp
FROM zooi z
)
SELECT sta,sto
, age(sto,sta) AS how_old
, (sto-sta)::time AS diff
FROM stamps;
Next step would be to convert the time (or interval) result to days or hours.

Dynamic (Column Based) Interval

How do I add a dynamic (column based) number of days to NOW?
SELECT NOW() + INTERVAL a.number_of_days "DAYS" AS "The Future Date"
FROM a;
Where a.number_of_days is an integer?
I usually multiply the number by interval '1 day' or similar, e.g.:
select now() + interval '1 day' * a.number_of_days from a;
I know this is a year old, but if you need to use a column to specify the actual interval (e.g. 'days', 'months', then it is worth knowing that you can also CAST your string to an Interval, giving:
SELECT now()+ CAST(the_duration||' '||the_interval AS Interval)
So the the original question would become:
SELECT now() + CAST(a.number_of_days||" DAYS" AS Interval) as "The Future Date" FROM a;
I prefer this way. I think its pretty easy and clean.
In Postgres you need interval to use + operator with timestamp
select (3||' seconds')::interval;
select now()+ (10||' seconds')::interval,now();
where you can use seconds, minutes, days, months...
and you can replace the numbers to your column.
select now()+ (column_name||' seconds')::interval,now()
from your_table;
Use make_interval()
SELECT NOW() + make_interval(days => a.number_of_days) AS "The Future Date"
FROM a;
But in general it might be a better idea to use a column defined as interval, then you can use any unit you want when you store a value in there.
To creating intervals those based on column values, I recommend to add two columns in your table. For example, column "period_value"::INT4 and column "period_name"::VARCHAR.
Column "period_name" can store the following values:
microsecond
milliseconds
second
minute
hour
day
week
month
quarter
year
decade
century
millennium
+--------------+-------------+
| period_value | period_name |
+--------------+-------------+
| 2 | minute |
+--------------+-------------+
Now you can write:
SELECT NOW() - (period_value::TEXT || ' ' || period_name::TEXT)::INTERVAL FROM table;
If we have field with interval string value such as '41 years 11 mons 4 days' and want to convert it to date of birth use this query :
UPDATE "february14" set dob = date '2014/02/01' - (patient_age::INTERVAL)
dob is date field to convert '41 years 11 mons 4 days' to '1972/10/14' for example
patient_age is varchar field that have string like '41 years 11 mons 4 days'
And this is query to convert age back to date of birth
SELECT now() - INTERVAL '41 years 10 mons 10 days';
Updating based on a column ID was a useful way to create some randomised test data for me.
update study_histories set last_seen_at = now() - interval '3 minutes' * id;