I've tried finding an answer to this question but haven't been entirely successful (or maybe I just don't understand the PostgreSQL documentation).
I am using this function in SQLite:
datetime (message.date / 1000000000 + strftime ("%s", "2001-01-01"), "unixepoch", "localtime")
message.date is a large integer that can be converted to a date starting in 1987 e.g. 550535817000000000
strftime gives me 978307200
I am attempting to recreate this function in postgresql but am definitely missing something because I keep getting errors or incorrect output. A few attempts are below:
// Gives SQL Error [42883]: ERROR: operator does not exist: timestamp with time zone + timestamp with time zone
Hint: No operator matches the given name and argument types. You might need to add explicit type casts. Position: 51
TO_TIMESTAMP((message.date / 1000000000)) + TO_TIMESTAMP('2001-01-01', 'YYYY-MM-DD HR24:MI:SS')
// Date in 1987 with TZ -7 e.g. 1987-05-12 16:36:38.000 -0700
TO_TIMESTAMP((message.date / 1000000000))
// 2001-01-01 00:00:00.000 -0800
TO_TIMESTAMP('2001-01-01', 'YYYY-MM-DD HR24:MI:SS'),
I'm pretty sure I'm missing something. Can anyone help direct me to the right solution?
UPDATE:
The solution below based on #matbalie 's feedback -- this date is based on Messages chat.db date in the message table.
to_timestamp((message.date / 1000000000)::integer + EXTRACT(EPOCH FROM '2001-01-01'::date)::integer) message_date,
Related
I am new to postgresql bot not to sql in general. I have a table that I need to read values from, on of the columns is a unix timestamp that I want to convert in to a more human readable format thus I found this:
SELECT lt,dw,up,to_char(uxts, 'YYYY-MM-DD HH24:MI:SS')
from products;
But that produces an error:
ERROR: multiple decimal points
I am lost here. I am sure someone can show me how to do it. The documentation isn't that clear to me. Postgresql 9.5 is the database.
to_char() converts a number, date or timestamp to a string, not the other way round.
You want to_timestamp()
Convert Unix epoch (seconds since 1970-01-01 00:00:00+00) to timestamp
So just apply that function on your column
SELECT lt,dw,up,to_timestamp(uxts) as uxts
from products;
This assumes that uxts is some kind of number data type (integer, bigint or double precision)
Using postgres 14
I have a timestamp something like this 2011-04-26T05:04:11Z. Its in UTC time
I tried converting it to a postgres timestamp using this function and i get a wrong result
2022-04-26 00:04:11-07. The time part seems messed up.
This is the query i have
select to_TIMESTAMP('2011-04-26T05:04:11Z','YYYY-MM-DDTHH:MI:SS')
If you just want to convert the string to a Postgres timestamp then:
select '2011-04-26T05:04:11Z'::timestamptz;
04/25/2011 22:04:11 PDT
The output will depend on the DateStyle setting.
To get your example to work then:
select to_TIMESTAMP('2011-04-26T5:04:11Z','YYYY-MM-DD"T"HH24:MI:SS');
to_timestamp
-------------------------
04/26/2011 05:04:11 PDT
Note the "T" this causes it to be ignored as that seems to be what is causing the issues. Not certain, but probably related to Postgres ISO format using a space instead of T. Quoting characters to be ignored comes from Formatting function:
Tip
Prior to PostgreSQL 12, it was possible to skip arbitrary text in the input string using non-letter or non-digit characters. For example, to_timestamp('2000y6m1d', 'yyyy-MM-DD') used to work. Now you can only use letter characters for this purpose. For example, to_timestamp('2000y6m1d', 'yyyytMMtDDt') and to_timestamp('2000y6m1d', 'yyyy"y"MM"m"DD"d"') skip y, m, and d.
There is no provision for a time zone abbreviation in to_timestamp so the Z will be ignored and the timestamp will be in local time with the same time value. That is why I made my first suggestion using the timestamptz cast.
Two ways to deal with time zone:
One:
select to_TIMESTAMP('2011-04-26T5:04:11Z','YYYY-MM-DD"T"HH24:MI:SS')::timestamp AT time zone 'UTC';
timezone
-------------------------
04/25/2011 22:04:11 PDT
Two:
select to_TIMESTAMP('2011-04-26T5:04:11+00','YYYY-MM-DD"T"HH24:MI:SS+TZH');
to_timestamp
-------------------------
04/25/2011 22:04:11 PDT
Recently there is an issue from my side.
In the table in redshift I have 2 columns:
The visit_time, which mentions the start time of the session and in YYYY-MM-DD HH:MM:SS format; Another column which is the time_spent, and it stands for the millesecond that user spends in certain page and currently it is in float(8)
What I want to do is to Add the visit_time with time_spent in second and convert it into YYYY-MM-DD HH:MM:SS, for example 2018-09-20 21:00:55 + 2 = 2018-09-20 21:00:57, so that I can get the visit_end_time. I tried to add it with date add function like this
Select
dateadd(SECOND,CAST (a.timeonpage AS DECIMAL)/1000 ,a.visit_time::date) time_left,
But it returns error: Invalid operation: function pg_catalog.date_add("unknown", double precision, date) does not exist
To do this, I tried to used the dateadd function like this:
Select
dateadd(SECOND,CAST (a.timeonpage AS INTEGER)/1000 ,a.visit_time::date) time_left,
It does not return error, but it returns the start of the date e.g 2018-09-23 00:00:00, which is not sth that I need.
What is the error that I made and how can I solve it?
Many thanks!
The dateadd function does require an integer for the interval. The problem with your second example is that when you cast a.visit_time to a date type it truncates it to the start of that day (removes the time component). Cast it to a timestamp instead:
select dateadd(second, round(a.timeonpage/1000.0)::integer, a.visit_time::timestamp);
select dateadd(second, round(2345/1000.0)::integer, '2018-09-20 21:00:55'::timestamp);
date_add
---------------------
2018-09-20 21:00:57
Also if you are storing visit_time as a string I would recommend making the column type a timestamp.
I've looked at many SO questions related to this but I can't seem to get anything to work. I'm not very good with semi complex SQL queries.
I want to get the difference between the current time and a column that is in unix timestamp in hours.
I'm not sure what I'm doing wrong or right for that matter. The goal is to only pull the rows that is less than 24 hours old. If there is a better way or example that works that would be great.
I tried several answers from here Timestamp Difference In Hours for PostgreSQL
I can't get this query to work no matter how many different ways I try it. wc.posted is a bigint store as unix timestamp
SELECT w.wal_id, wc.com_id, w.posted AS post_time, wc.posted AS com_time
FROM wall as w LEFT JOIN wall_comments as wc ON w.wal_id=wc.wal_id
WHERE (EXTRACT(EPOCH FROM wc.posted)) > current_timestamp - interval '24 hours'
Then the Error:
ERROR: function pg_catalog.date_part(unknown, bigint) does not exist
LINE 1: ... wall_comments as wc ON w.wal_id=wc.wal_id WHERE (EXTRACT(EP...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
********** Error **********
ERROR: function pg_catalog.date_part(unknown, bigint) does not exist
SQL state: 42883
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Character: 148
Here is a simplified fiddle
From the fine manual:
A single-argument to_timestamp function is also available; it accepts a double precision argument and converts from Unix epoch (seconds since 1970-01-01 00:00:00+00) to timestamp with time zone. (Integer Unix epochs are implicitly cast to double precision.)
So to convert your bigint seconds-since-epoch to a timestampz:
to_timestamp(wc.posted)
Perhaps you're looking for this:
WHERE to_timestamp(wc.posted) > current_timestamp - interval '24 hours'
Try:
SELECT EXTRACT(EPOCH FROM (timestamp_B - timestamo_A))
FROM TableA
Details here: EXTRACT.
Try this out i am sure this will help you
select field_1,field_2,field_3 from schema_name.table_name Where
ROUND(EXTRACT(EPOCH FROM (cast(now() as timestamp) - cast(your_time_field as timestamp)))/60) > 1440;
The error message anounce :
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Indeed, the simplest solution is to add an explicit timestamp type cast
SELECT w.wal_id, wc.com_id, w.posted AS post_time, wc.posted AS com_time
FROM wall as w LEFT JOIN wall_comments as wc ON w.wal_id=wc.wal_id
WHERE (EXTRACT(EPOCH FROM wc.posted::timestamp)) > current_timestamp - interval '24 hours'
Notice the cast :
wc.posted::timestamp
When ececute the following SQL syntax in Oracle, always not success, please help.
40284.3878935185 represents '2010-04-16 09:18:34', with microsecond.
an epoch date of 01 January 1900 (like Excel).
create table temp1 (date1 number2(5,10));
insert into temp1(date1) values('40284.3878935185');
select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1
Error report: SQL Error: ORA-01861: literal does not match format
string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Thanks to Mark Bannister
Now the SQL syntax is:
select to_char(to_date('1899-12-30','yyyy-mm-dd') +
date1,'yyyy-mm-dd hh24:mi:ss') from temp1
but can't fetch the date format like 'yyyy-mm-dd hh24:mi:ss.ff'. Continue look for help.
Using an epoch date of 30 December 1899, try:
select to_date('1899-12-30','yyyy-mm-dd') + date1
Simple date addition doesn't work with timestamps, at least if you need to preserve the fractional seconds. When you do to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (in a comment on Mark's answer) the TIMESTAMP is implicitly converted to a DATE before the addition, to the overall answer is a DATE, and so doesn't have any fractional seconds; then you use to_char(..., '... .FF') it complains with ORA-01821.
You need to convert the number of days held by your date1 column into an interval. Fortunately Oracle provides a function to do exactly that, NUMTODSINTERVAL:
select to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY') from temp3;
16-APR-10 09.18.33.999998400
You can then display that in your desired format, e.g. (using a CTE to provide your date1 value):
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;
2010-04-16 09:18:33.999998400
Or to restrict to thousandths of a second:
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;
2010-04-16 09:18:33.999
An epoch of 1899-12-30 sounds odd though, and doesn't correspond to Excel as you stated. It seems more likely that your expected result is wrong and it should be 2010-04-18, so I'd check your assumptions. Andrew also makes some good points, and you should be storing your value in the table in a TIMESTAMP column. If you receive data like this though, you still need something along these lines to convert it for storage at some point.
Don't know the epoch date exactly, but try something like:
select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;
Or, cast to timestamp like:
select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;
I hope this doesn't come across too harshly, but you've got to totally rethink your approach here.
You're not keeping data types straight at all. Each line of your example misuses a data type.
TEMP1.DATE1 is not a date or a varchar2, but a NUMBER
you insert not the number 40284.3878935185, but the STRING >> '40284.3878935185' <<
your SELECT TO_DATE(...) uses the NUMBER Temp1.Date1 value, but treats it as a VARCHAR2 using the format block
I'm about 95% certain that you think Oracle transfers this data using simple block data copies. "Since each Oracle date is stored as a number anyway, why not just insert that number into the table?" Well, because when you're defining a column as a NUMBER you're telling Oracle "this is not a date." Oracle therefore does not manage it as a date.
Each of these type conversions is calculated by Oracle based on your current session variables. If you were in France, where the '.' is a thousands separator rather than a radix, the INSERT would completely fail.
All of these conversions with strings are modified by the locale in which Oracle thinks your running. Check dictionary view V$NLS_PARAMETERS.
This gets worse with date/time values. Date/time values can go all over the map - mostly because of time zone. What time zone is your database server in? What time zone does it think you're running from? And if that doesn't spin your head quite enough, check out what happens if you change Oracle's default calendar from Gregorian to Thai Buddha.
I strongly suggest you get rid of the numbers ENTIRELY.
To create date or date time values, use strings with completely invariant and unambiguous formats. Then assign, compare and calculate date values exclusively, e.g.:
GOODFMT constant VARCHAR2 = 'YYYY-MM-DD HH24:MI:SS.FFF ZZZ'
Good_Time DATE = TO_DATE ('2012-02-17 08:07:55.000 EST', GOODFMT);