Convert milliseconds to Date/Time - sql

I'm trying to generate a report in PostgreSQL.
It's working -- except one column stored in the database represents a date/time value, but it is stored as an integer representing the number of milliseconds since 1970.
Needless to say, the millisecond value has not much meaning to people reading the report.
Is there a way in SQL to convert milliseconds into some sort of readable date/time value?
I'm not easily able to have the report generated in some other program or language. I'd like the report to be run as a SQL script.

This recipe is from the docs:
SELECT TIMESTAMP WITH TIME ZONE 'epoch' + (millisecond_column/1000) * INTERVAL '1 second'
FROM mytable;
Recent versions of PostgreSQL provide a to_timestamp function to achieve the same.

Related

Using the To_Date function is not converting to the expected format

I'm trying to convert a char (output from a substr operation) into a dateTime format using TO_DATE with the following format - hh24:mi:ss.
The output of the substr looks fine but as soon as I run it through the TO_DATE function it converts every row for this column into 01-MAR-22.
To demonstrate I have the following:-
SUS_TIME2 shows what I get back from the SUBSTR and it looks fine at this point. SUS_TIME3 then shows what I get back after running it through the TO_DATE function, this where it converts it to 01-MAR-22
,SUBSTR((s.resolve_date-suspend_date),-16,9) sus_time2
,TO_DATE(SUBSTR((s.resolve_date-suspend_date),-16,9), 'hh24:mi:ss') sus_time3
Can anyone see what's going on here please? Thanks
Dates are stored in an internal representation and do not have any intrinsic format. What you are seeing is how your client is choosing to format the actual date value as a string for display, using your session's NLS_DATE_FORMAT setting (not always the case, but this is SQL Developer, so it is here.)
When you call to_date() with only the time components it defaults the date part to the first day of the current month, which is why you are seeing March 1st. That is a bit buried in the documentation:
If you specify a date value without a time component, then the default time is midnight. If you specify a date value without a date, then the default date is the first day of the current month.
But it is setting the time properly on that date, which you can see by either explicitly converting the date back to a string:
to_char(<your date>, 'YYYY-MM-DD HH24:MI:SS')
or by changing your session:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'
db<>fiddle
But you should not rely on NLS settings for anything except ad hoc queries; someone else running your code may have different settings. And only convert back to a string at the last moment when you have to display the value in a particular format - store it and pass it around as a native date.
Oracle doesn't have a time-only data type, so if you really only care about the time part then you can use a date (either defaulting to current month, or using an explicit fixed date) and ignore the date part; or potentially use an interval; or use the number of seconds the time represents (i.e. 0-86399). Which is suitable depends on what you'll use the value for.
It looks like you might be substringing the result of subtracting two timestamps; in which case (a) you already have an interval, and (b) you probably need to allow for that difference to span more than one day. You can also extract the individual time components directly from an interval value. So I'd question whether your approach is really appropriate.
You appear to be calculating s.resolve_date-suspend_date which gives you an INTERVAL DAY TO SECOND data type (implying that one or both of s.resolve_date or suspend_date is a TIMESTAMP data type) and then using SUBSTR to extract the time component of the data type and trying to convert that to a date and then display the time component.
Don't do that as using SUBSTR is fragile as it depends on the number of decimal places that the INTERVAL has which, in turn, will depend on the number of fractional seconds that the TIMESTAMP values have.
Just pick a date and add the interval to it and then format it as string to display it:
SELECT s.resolve_date,
suspend_date,
TO_CHAR(
DATE '1900-01-01' + (s.resolve_date-suspend_date),
'hh24:mi:ss'
) sus_time
FROM table_name s
Which, for the sample data:
CREATE TABLE table_name (resolve_date, suspend_date) AS
SELECT CAST(SYSTIMESTAMP AS TIMESTAMP(6)),
CAST(TRUNC(SYSTIMESTAMP) AS TIMESTAMP(6))
FROM DUAL;
Outputs:
RESOLVE_DATE
SUSPEND_DATE
SUS_TIME
2022-03-25 12:59:15.223445
2022-03-25 00:00:00.000000
12:59:15
From your comment:
all i'm trying to do is format the data so that when it's exported to Excel sorting works correctly.
That really is an XY-problem. You can solve it in Excel by either specifying the column format as a time when you import the data into Excel or right-click on the column header and "Format" the column picking the "time" data type with the correct format model.
You can also output the time as a fraction of a day with a numeric data type and then Excel can format it as the correct time using either:
SELECT s.resolve_date,
suspend_date,
MOD(CAST(s.resolve_date AS DATE)-CAST(suspend_date AS DATE), 1) AS sus_time
FROM table_name s;
or
SELECT s.resolve_date,
suspend_date,
TO_CHAR(DATE '1900-01-01' + (s.resolve_date-suspend_date), 'SSSSS')
/ 86400 AS sus_time
FROM table_name s
Which both output:
RESOLVE_DATE
SUSPEND_DATE
SUS_TIME
2022-03-25 13:16:40.204461
2022-03-25 00:00:00.000000
.5532407407407407407407407407407407407407
Which may not be human readable in that format but Excel will reformat it in a time column to 13:16:40.
db<>fiddle here

How to extract time from CURRENT_TIMESTAMP in Postgresql

Just as we are able to extract the date from timestamps in Postgresql using date(CURRENT_TIMESTAMP), I was wondering if there's a equivalent function to extract time. (formatted as hh:mm:ss)
I want to be able to compare a time value, stored in a column with the time datatype (see https://www.postgresql.org/docs/current/datatype-datetime.html), to the current time just using an SQL query.
Any suggestions are most welcome!
You can either use current_time or casting a timestamp to time: current_timestamp::time
e.g.
where the_time_column >= current_time - interval '6' hour
For details, see Current Date/Time in the Postgres manual

Cast integer with hour to time in PostgreSQL

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?

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.

inserting current system time in table through a keyword using sql query

just like sysdate inserts the current date,
Is there any way to insert only the current time using a sql query.
for example *insert into table_name values(sysdate); *
There is no Oracle data type that represents just a hours/minutes/seconds. There is DATE and the various TIMESTAMP types that represents a point in time, including date and time. You don't say why you're trying to store this, but you could store the time as an offset in a NUMBER column, as fractions of a day.
So, if you wanted to find store the time of day that a store opens on Monday, you'd do:
TRUNC( SYSDATE ) + offset