Cast integer with hour to time in PostgreSQL - sql

I have a number passed as integer and would like to convert it to time, and use this number as hour.
I have found solutions for using a number as minutes, but I'm not familiar with PostgreSQL syntax. Not sure what to do here:
select CAST(to_char(czas, 'FM99909:99') AS TIME WITHOUT
TIME ZONE)::TIME from test
The result would be:
00:15:00
But I'm looking for a way to make it:
15:00:00
I have been working with MS SQL for quite a while, I'm surprised how much more complex PostgreSQL syntax is.

If your column test.czas to signifies hours just multiply with interval '1 hour':
SELECT (interval '01:00' * czas)::time FROM test;
Produces your desired result exactly, even with fractional digits.
'01:00' and '1 hour' are equivalent interval literals.
For czas > 24 you get the remainder (full days cut off) - like if you'd use czas%24.
Related:
Postgres data type cast
How do I add a column to a date in Postgres?

Related

Difference between 2 timestamps in Oracle SQL

Please help in finding the difference between 2 timestamps in SQL
I tried using
Select (cast(sysdate as timestamp) - cast(sysdate-2 as timestamp)) diff from dual;
I got 'ORA-00911:invalid character' error
If you want something that looks a bit simpler, try this for finding events in a table which occurred in the past 1 minute:
With this entry you can fiddle with the decimal values till you get the minute value that you want. The value .0007 happens to be 1 minute as far as the sysdate significant digits are concerned. You can use multiples of that to get any other value that you want:
select (sysdate - (sysdate - .0007)) * 1440 from dual;
Result is 1 (minute)
Then it is a simple matter to check for
select * from my_table where (sysdate - transdate) < .00071;
You are not finding the difference between two timestamps; you are finding the difference between two dates and casting them to timestamps in the process. This is unnecessary and you can just leave them as date values and explicitly cast the difference to an INTERVAL DAY TO SECOND data type (which would be the output if you used timestamps):
SELECT (SYSDATE - (SYSDATE - 2)) DAY TO SECOND AS diff
FROM DUAL;
Which outputs the interval:
DIFF
+02 00:00:00.000000
However, your code works db<>fiddle.
You will probably find that the error:
ORA-00911:invalid character
Is nothing to do with your query and is related to the ; statement terminator at the end. If you are running your query through a 3rd-party application (i.e. C#, Java, Python, etc.) then they will pass single statements to the database to execute and, in this case, having the statement terminator is invalid syntax (as there will only be one SQL statement) and you just need to remove it.

How to create a composite datetime with fixed date + random time interval in Postgresql

I'm new to Postgresql, and I'm looking for a way to return a composite datetime, built with a fixed date, and a random time, defined as an interval.
An example:
2020-12-02 10:00:00
2020-12-02 10:10:20
2020-12-02 08:25:23
2020-12-02 09:12:11
As you can see the date is fixed, and time remains between 08:00:00 and 10:30:00.
Do you know how to replicate this behaviour using a Postgresql query?
I would suggest:
select '2020-12-02 08:00:00'::timestamp + random() * interval '2 hour 30 minute'
Or, for the current date, you could express this as:
select current_date + interval '08:00:00' + random() * interval '02:30'
Note that these illustrate two different ways of expressing an interval with 2 hours and 30 minutes (and not even giving interval '150 minute' as an example).
As a total newbie of Postgresql (but with some experience in general SQL), and reading some posts here, I've found an easy way to get it done:
SELECT
CURRENT_DATE + time '08:00:00' +
(random() * interval '3 hours')::time
AS date_wrandom_t
FROM generate_series(1, 50)
generate_series its here only to demonstrate some results, you can omit it and get a single result.
What it does:
Takes the current date (today)
Defines the starting time (min value)
Generate a random interval of 3 hours - (tested with SELECT (random() * interval '3 hours')::time)
Add the result to the minimum time (08:00:00)
Maybe it's not the best solution, but I like it as it's based on a simple syntax, easy to remember.
I wish to find some time to study this DBMS, it seems really powerful.
Any addition/suggestion is welcome!

Timestamp query to hours

I need some help with timestamps with postgresql. I have a column for the timestamp with timezone named download_at for when a user downloaded an app and a column user_id which is an integer. I am trying to extract user IDs of users that have downloaded within the last 168 hours from the last 60 days of information. I am a bit confused on how I can approach this and felt stuck because of the two different times. I believe I might have to play around with the trunc function but felt a bit stuck.
A basic example:
SELECT *
FROM table1
WHERE download_at > now() - '186 hours'::interval
Postgres is phenomenal at handling dates and times. A breakdown of what this does:
now() --function that returns the current time as a datetime object
'186 hours'::interval --a string cast to an interval
In postgres :: does casting. When casting to an interval Postgres will turn formatted English to an interval object. Since you can subtract datetime and interval objects it'll do the rest for you.

Timestamp Difference In Hours for PostgreSQL

Is there a TIMESTAMPDIFF() equivalent for PostgreSQL?
I know I can subtract two timestamps to get a postgresql INTERVAL. I just want the difference between the two timestamps in in hours represented by an INT.
I can do this in MySQL like this:
TIMESTAMPDIFF(HOUR, links.created, NOW())
I just need the difference between two timestamps in hours represented as an integer.
Solution works for me:
SELECT "links_link"."created",
"links_link"."title",
(EXTRACT(EPOCH FROM current_timestamp - "links_link"."created")/3600)::Integer AS "age"
FROM "links_link"
The first things popping up
EXTRACT(EPOCH FROM current_timestamp-somedate)/3600
May not be pretty, but unblocks the road. Could be prettier if division of interval by interval was defined.
Edit: if you want it greater than zero either use abs or greatest(...,0). Whichever suits your intention.
Edit++: the reason why I didn't use age is that age with a single argument, to quote the documentation: Subtract from current_date (at midnight). Meaning you don't get an accurate "age" unless running at midnight. Right now it's almost 1am here:
select age(current_timestamp);
age
------------------
-00:52:40.826309
(1 row)
Get fields where a timestamp is greater than date in postgresql:
SELECT * from yourtable
WHERE your_timestamp_field > to_date('05 Dec 2000', 'DD Mon YYYY');
Subtract minutes from timestamp in postgresql:
SELECT * from yourtable
WHERE your_timestamp_field > current_timestamp - interval '5 minutes'
Subtract hours from timestamp in postgresql:
SELECT * from yourtable
WHERE your_timestamp_field > current_timestamp - interval '5 hours'
Michael Krelin's answer is close is not entirely safe, since it can be wrong in rare situations. The problem is that intervals in PostgreSQL do not have context with regards to things like daylight savings. Intervals store things internally as months, days, and seconds. Months aren't an issue in this case since subtracting two timestamps just use days and seconds but 'days' can be a problem.
If your subtraction involves daylight savings change-overs, a particular day might be considered 23 or 25 hours respectively. The interval will take that into account, which is useful for knowing the amount of days that passed in the symbolic sense but it would give an incorrect number of the actual hours that passed. Epoch on the interval will just multiply all days by 24 hours.
For example, if a full 'short' day passes and an additional hour of the next day, the interval will be recorded as one day and one hour. Which converted to epoch/3600 is 25 hours. But in reality 23 hours + 1 hour should be a total of 24 hours.
So the safer method is:
(EXTRACT(EPOCH FROM current_timestamp) - EXTRACT(EPOCH FROM somedate))/3600
As Michael mentioned in his follow-up comment, you'll also probably want to use floor() or round() to get the result as an integer value.
You can use the "extract" or "date_part" functions on intervals as well as timestamps, but I don't think that does what you want. For example, it gives 3 for an interval of '2 days, 3 hours'. However, you can convert an interval to a number of seconds by specifying 'epoch' as the time element you want: extract(epoch from '2 days, 3 hours'::interval) returns 183600 (which you then divide by 3600 to convert seconds to hours).
So, putting this all together, you get basically Michael's answer: extract(epoch from timestamp1 - timestamp2)/3600. Since you don't seem to care about which timestamp precedes which, you probably want to wrap that in abs:
SELECT abs(extract(epoch from timestamp1 - timestamp2)/3600)
postgresql get seconds difference between timestamps
SELECT (
(extract (epoch from (
'2012-01-01 18:25:00'::timestamp - '2012-01-01 18:25:02'::timestamp
)
)
)
)::integer
which prints:
-2
Because the timestamps are two seconds apart. Take the number and divide by 60 to get minutes, divide by 60 again to get hours.
extract(hour from age(now(),links.created)) gives you a floor-rounded count of the hour difference.
To avoid the epoch conversion you could extract the days multiply them by 24 and add the extraction of hours to it.
select current_timestamp, (current_timestamp - interval '500' hour), (extract(day from (current_timestamp - (current_timestamp - interval '500' hour)) * 24) + extract(hour from (current_timestamp - (current_timestamp - interval '500' hour))));
For MySQL timestampdiff I don't know, but for MSSQL datediff(hour, start, end) the best equivalent in PostgreSQL is floor(extract(epoch from end - start)/3600), because in MSSQL select datediff(hour,'2021-10-31 18:00:00.000', '2021-10-31 18:59:59.999') return 0
This might sound crazy to a lot of developers who like to take advantage of database functions,
But after exhaustive problems thinking, creating and bugfixing applications for mysql and postgrsql with php comparing date functions, I've come to the conclusion (for myself), that the easiest way, that is the simplest with less SQL headaches is not to take advantage of any of them.
Why? because if you are developing in a middleware language like PHP, PHP has all of these functions, and they are easier to implement in the application ode as comparing integers. PostgreSQL timestamp is NOT == UNIX TIMESTAMP and MySQL's UNIX TIMESTAMP is NOT PostgresQL's or Oracles timestamp.. it gets harder to port if you use database timestamps..
so just use an integer, not a timestamp,
as the number of seconds since january 1st 1970 midnight. and never mind database timestamps.
, and use gmdate() and store everything as gmt time to avoid timezone issues.
if you need to search, sort or compare the day from other data, or the month or the year or the day of the week, or anything, in your application,
and INTEGER datatype for time_day, time_hour, time_seconds.. or whatever you wnat to index to be searched will make for smoother and more portable databases.
you can just use one field, in most instances: INTEGER time_created NOT NULL
(more fields in your database row is the only drawback to this solution that i have found, and that doesnt cause as many headaches, or cups of coffee :)
php's date functions are outstanding to compare dates,
but in mysql or postgresql, comparing dates ? nah.. use integer sql comparisons
i realize it may SEEM easier to use CURRENT_TIMESTAMP on an insert function. HA!
don't be fooled.
You cant do DELETE FROM SESSION_TABLE WHERE time-initialized < '2 days'
if time-intitialized is a postgresql timestamp.
but you CAN do:
DELETE FROM SESSION_TABLE WHERE time_initialized < '$yesterday'
As long as you set $yesterday in php as the integer of seconds since 1970 that yesterday was.
This is easier housekeeping of session records than comparing timestamps in postgresql select statements.
SELECT age(), SELECT extract(), and asbtime are headaches in an of themselves. this is just my opinion.
you can do addition, substraction, <, >, all with php date objects
_peter_sysko
U4EA Networks, Inc.

SQL to extract matlab date from postgres db

I'd like to construct a query to "convert" a postgresql datetime to a matlab datenum. Experience with other DBs has shown me that converting the date on the DB side is much faster than doing it in matlab.
Matlab stores dates as number of days (including fractions) since an arbitrary epoch of a gregorian, non-existent date of 00-00-0000.
On Oracle, it's simple, because Oracle stores dates internally like matlab does, but with a different epoch.
select (date_column_name - to_date('01-Jan-0001') + 365) ...
A straightforward conversion of this to PG syntax doesn't work:
select (date_column_name - date '01-Jan-0001' + interval 365) ...
I've started with a particular day in matlab, for testing:
>> num2str(datenum('2010-10-02 12:00'))
ans =
734413.5
I've been in and out of the pg docs all day, extracting epochs and seconds, etc. And I've gotten close. Basically this gets the seconds in an interval, which I just divide by the seconds in a day:
Select cast(extract(epoch from (timestamp '2010-10-02 12:00'
- timestamp '0000-01-01 23:10'
+ interval '2 day'
)
) as real
)/(3600.0*24.0) AS MDate
answer:
734413.51111111111
But that exhibits some bizarre behavior. Adjusting the minutes from the epoch timestamp doesn't change the answer, except at one particular minute - i.e 23:09 is one answer, 23:10 is another, and it stays the same from 23:10 to 23:59. (other hours have similar behavior, though the particular "minute" is different.)
Any ideas? Maybe on another way to do this?
edit:
using 8.4.2
Well, extract(epoch from t::timestamp) will give seconds since the UNIX epoch (01 Jan 1970), and produces 1286017200 for '2010-10-02 12:00:00'.
Matlab gives 734413.5 for the same timepoint, but that's in days- so 63453326400 seconds, an offset of 62167309200.
So to convert postgres epoch time to matlab datenum, we should be able to just add that offset and convert back to days.
steve=# select (extract(epoch from '2010-10-02 12:00:00'::timestamp) + 62167309200) / (24*3600);
?column?
----------
734413.5
(1 row)
It seems that the cast was the problem.
Select extract(epoch from (timestamp '2010-10-02 12:00:01'
- timestamp '0000-01-01 00:00'
+ interval '1 day'))/(3600.0*24.0)
works like a champ.