Convert Oracle Date into RFC 3339 Format - sql

I have a date field in oracle which returns
17-APR-19 12:00:00 AM
I also have a time column (VARCHAR) which returns HHMM in Military
1810
I'd like to combine these two fields to create a timestamp that is formatted to RFC 3339 standards. Preferable like this.
2019-04-17T18:10:00Z
I can convert a timestamp into the correct time using this:
SELECT
TO_CHAR(
SYSTIMESTAMP AT TIME ZONE 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss"Z"'
)
FROM dual;
Is there a way to convert my date and time field into this timestamp format? The time on the date field is incorrect and needs to be replaced by the time field.

You can TRUNCate your date back to midnight and then use NUMTODSINTERVAL to add hours and minutes to it to get the correct time component:
Oracle Setup:
CREATE TABLE your_table ( your_date_column, your_time_column ) AS
SELECT DATE '2019-04-17', '1810' FROM DUAL
Query:
SELECT TO_CHAR(
TRUNC( your_date_column )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 1, 2 ), 'HOUR' )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 3, 2 ), 'MINUTE' ),
'YYYY-MM-DD"T"HH24:MI:SS"Z"'
) AS combined_date_time
FROM your_table
Output:
| COMBINED_DATE_TIME |
| :------------------- |
| 2019-04-17T18:10:00Z |
db<>fiddle here
If you want the value as a TIMESTAMP WITH TIME ZONE then:
SELECT CAST(
TRUNC( your_date_column )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 1, 2 ), 'HOUR' )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 3, 2 ), 'MINUTE' )
AS TIMESTAMP
) AT TIME ZONE 'UTC' AS combined_date_time
FROM your_table

Just do a bit of string concatenation
to_char( your_date, 'yyyy-mm-dd' ) ||
'T' ||
substr( your_time, 1, 2 ) ||
':' ||
substr( your_time, 3, 2 ) ||
':00Z'
assuming that your_time is always 4 characters long (i.e. 2 AM is represented as the string '0200' rather than '200'). This also assumes that the seconds will always be '00'.

You can achieve this by converting your_number into minutes and add it to your date, then cast it to timestamp as following:
SELECT CAST(
your_date +
(FLOOR(YOUR_TIME/100)*60 + MOD(YOUR_TIME,100)) / 1440
AS TIMESTAMP
) AT TIME ZONE 'UTC' AS YOUR_TIME_STAMP
FROM your_table;
Cheers!!

Related

How to unite two columns of date + time for datediff - Oracle sql

I have two int columns:
thedate - for example 20210512
thetime - for example 142342
So, i need to unite them to one column to check if the time difference is lower the 5.
I tried this:
TO_DATE(sysdate) - TO_DATE(thedate, 'YYYY-MM-DD') < 5
But it only for the date not for the time so i will be glad to know how to unite the two int columns + and convert it to date type for time difference.
You can use:
SELECT *
FROM table_name
WHERE TO_DATE( thedate * 1000000 + thetime, 'YYYYMMDDHH24MISS' ) > SYSDATE - 5;
Which, for the sample data:
CREATE TABLE table_name ( thedate INT, thetime INT );
INSERT INTO TABLE_NAME ( thedate, thetime ) VALUES (
TO_NUMBER( TO_CHAR( SYSDATE, 'YYYYMMDD' ) ),
TO_NUMBER( TO_CHAR( SYSDATE, 'HH24MISS' ) )
);
INSERT INTO TABLE_NAME ( thedate, thetime ) VALUES (
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '4 23' DAY TO HOUR, 'YYYYMMDD' ) ),
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '4 23' DAY TO HOUR, 'HH24MISS' ) )
);
INSERT INTO TABLE_NAME ( thedate, thetime ) VALUES (
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '5 1' DAY TO HOUR, 'YYYYMMDD' ) ),
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '5 1' DAY TO HOUR, 'HH24MISS' ) )
);
Outputs:
THEDATE
THETIME
20210512
131832
20210507
141832
Or, if you want to use indexes on the thedate and thetime columns (the query above would not use indexes on thedate and thetime columns but would require a function-based index) then:
SELECT *
FROM table_name
WHERE thedate > TO_NUMBER( TO_CHAR( SYSDATE - 5, 'YYYYMMDD' ) )
OR ( thedate = TO_NUMBER( TO_CHAR( SYSDATE - 5, 'YYYYMMDD' ) )
AND thetime >= TO_NUMBER( TO_CHAR( SYSDATE - 5, 'HH24MISS' ) )
)
However, the better solution is to use appropriate data-types for your data; in this case, you should store date values in a DATE data-type (which, in Oracle, contains year-second components) rather than as two INT values for date and time.
db<>fiddle here
You want to convert to a timestamp, not a date. So:
select to_timestamp(cast(20210512 * 1000000 + 142342 as varchar2(255)), 'YYYYMMDDHH24MISS')
from dual;
Here is a db<>fiddle showing that this works.
Or in a where clause:
to_timestamp(cast(thedate * 1000000 + thetime as varchar2(255)), 'YYYYMMDDHH24MISS') > sysdate - interval '5' day
(or whatever you mean by "5").
Note: You may want to add a computed column to the table that has the full timestamp:
alter table t add column timestamp generated always as
( to_timestamp(cast(thedate * 10000 + thetime as varchar2(255)), 'YYYYMMDDHH24MISS') );

What would be the best way to filter part of the timestamp?

For example, I have a TIMESTAMP field and a record is something like '2021-04-23 14:17:46' in my database, and I want to find the records that start with '2021-04-23', that is a part of the TIMESTAMP, in SQL. What would be the best way to filter part of the timestamp?
And the other way around? If I have something like '2021-03-04' and I want to find all the timestamps that are yyyy-MM-dd HH: mm: ss
If your parameter is a valid date string, use date arithmetic. For example
-- parameter
with prm as (
select '2021-04-23' pd from dual
),
-- sample data
tbl(Code, Dt) as (
select 'c1', TIMESTAMP '2021-04-23 12:17:46' from dual union all
select 'c2', TIMESTAMP '2021-04-24 14:17:46' from dual
)
--
select tbl.*
from tbl
cross join prm
where dt >= TO_DATE(prm.pd, 'YYYY-mm-DD') and dt < TO_DATE(prm.pd, 'YYYY-mm-DD') + 1
order by code, dt
select dttm_col
from table
where to_date(dttm_col) = '2020-01-20'
The simple way is to TRUNCate the timestamp and compare it to a literal:
SELECT *
FROM table_name
WHERE TRUNC( timestamp_column ) = DATE '2021-04-23'
This may be simple but its not the best solution as Oracle will not use any index on the timestamp_column and will perform a full table scan; to use an index you would need to create a function-based-index on TRUNC( timestamp_column ).
The better way, although slightly more complicated, is to compare on a range of values using a TIMESTAMP literal:
SELECT *
FROM table_name
WHERE timestamp_column >= TIMESTAMP '2021-04-23 00:00:00'
AND timestamp_column < TIMESTAMP '2021-04-23 00:00:00' + INTERVAL '1' DAY;
or, using DATE literals:
SELECT *
FROM table_name
WHERE timestamp_column >= DATE '2021-04-23'
AND timestamp_column < DATE '2021-04-23' + INTERVAL '1' DAY;
If you want to compare to a string, rather than a literal, then use TO_TIMESTAMP:
SELECT *
FROM table_name
WHERE timestamp_column >= TO_TIMESTAMP( '2021-04-23', 'YYYY-MM-DD' )
AND timestamp_column < TO_TIMESTAMP( '2021-04-23', 'YYYY-MM-DD' ) + INTERVAL '1' DAY;
or, to remove the time component:
SELECT *
FROM table_name
WHERE timestamp_column >= TO_TIMESTAMP( SUBSTR( '2021-04-23 14:17:46', 1, 10 ), 'YYYY-MM-DD' )
AND timestamp_column < TO_TIMESTAMP( SUBSTR( '2021-04-23 14:17:46', 1, 10 ), 'YYYY-MM-DD' ) + INTERVAL '1' DAY;

Replacing specific date with a empty value in Oracle denodo

I have a view where I am selecting a date column and reading it as a local date in denodo. In my column, I have a date '00-Jan-1900' like this which is giving issue so I wanted to replace this with empty.
When I run this query, I get results as shown in the table2. But what I want is just an empty record in place of this date and looking like TABLE3.
Query:
select
to_localdate('dd-MM-yyyy', substring(replace("DATE", '00-Jan-1900', ''), 0, 10)) AS dtm
from XX
Table1:
DATE
22-Dec-2016
00-Jan-1900
30-Sep-2014
After replacing the date i get
Table2:
DATE
0201-12-22
0201-09-30
Is there a way i get output table like this?
TABLE3:
DATE
22-Dec-2016
30-Sep-2014
In my column, I have a date '00-Jan-1900' like this which is giving issue so I wanted to replace this with empty.
In Oracle, you can use:
UPDATE table_name
SET value = NULL
WHERE EXTRACT( DAY FROM value ) = 0;
If you have the table:
CREATE TABLE table_name ( value DATE );
Then, some extra hoops need to be jumped through to insert an invalid date (namely generating the date from binary data so that the normal validation process for date values can be skipped) by creating this function:
CREATE FUNCTION createDate(
year int,
month int,
day int,
hour int,
minute int,
second int
) RETURN DATE DETERMINISTIC
IS
hex CHAR(14);
d DATE;
BEGIN
hex := TO_CHAR( FLOOR( year / 100 ) + 100, 'fm0X' )
|| TO_CHAR( MOD( year, 100 ) + 100, 'fm0X' )
|| TO_CHAR( month, 'fm0X' )
|| TO_CHAR( day, 'fm0X' )
|| TO_CHAR( hour + 1, 'fm0X' )
|| TO_CHAR( minute + 1, 'fm0X' )
|| TO_CHAR( second + 1, 'fm0X' );
DBMS_OUTPUT.PUT_LINE( hex );
DBMS_STATS.CONVERT_RAW_VALUE( HEXTORAW( hex ), d );
RETURN d;
END;
/
Then, you can have the data:
INSERT INTO table_name ( value )
SELECT DATE '1900-01-01' FROM DUAL UNION ALL
SELECT createDate( 1900, 1, 0, 0, 0, 0 ) FROM DUAL;
and:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
SELECT value,
TO_CHAR( value, 'YYYY-MM-DD HH24:MI:SS' ) AS string_value
FROM table_name;
Outputs:
VALUE | STRING_VALUE
:------------------ | :------------------
1900-01-01 00:00:00 | 1900-01-01 00:00:00
1900-01-00 00:00:00 | 0000-00-00 00:00:00
To get rid of your invalid value, you can use:
UPDATE table_name
SET value = NULL
WHERE EXTRACT( DAY FROM value ) = 0;
Then:
SELECT value,
TO_CHAR( value, 'YYYY-MM-DD HH24:MI:SS' ) AS string_value
FROM table_name;
Outputs:
VALUE | STRING_VALUE
:------------------ | :------------------
1900-01-01 00:00:00 | 1900-01-01 00:00:00
null | null
db<>fiddle here
Is there a way i get output table like this?
TABLE3:
DATE
22-Dec-2016
30-Sep-2014
You can use:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-Mon-YYYY';
And then just run your query and it should change the output (but you will need to make sure the format is set in future sessions when you run the query).
Or you can specify the format model using TO_CHAR:
SELECT TO_CHAR( your_column, 'DD-Mon-YYYY' ) AS your_column
FROM your_table

SQL Vertica Timestamp

I have three values viz. a date value, an integer representing hour and an integer representing minute value.
I concatenated the three to form a timestamp like string:
CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT( CAST(<DATE_VALUE> AS CHAR(10)) , 'T') , CAST(<hour_value> AS CHAR(2))) , ':' ) , CAST(<minutes_value> AS CHAR(2))) , ':' ) , '00' )
Now how do I convert the above created timestamp field another timezone (i.e to EST) ?
Thanks.
You want to use AT TIME ZONE 'EST' but you will need to convert what you have to a timestamp first.
Also, you could just do something like: (VIZ + HR/24 + MIN/24/60) AT TIME ZONE 'EST' instead of all the string contortions. Or you could use INTERVAL like: ( VIZ + (HR::INTERVAL HOUR) + (MIN::INTERVAL MINUTE) ) AT TIME ZONE 'EST'
Example:
=> select ( VIZ + (HR::INTERVAL HOUR) + (MIN::INTERVAL MINUTE) ) AT TIME ZONE 'EST' AS MY_TS
-> FROM (select trunc(now()) AS VIZ, 5 AS HR, 45 AS MIN) x;
MY_TS
------------------------
2015-09-03 05:45:00-05
(1 row)

removing milliseconds from a oracle tmstmp field

I have a TIMESTAMP(6) field in Oracle and I need to remove the millisecond component from the time.
For example I have
10/20/2014 10:34:06.356000 AM
and I would like to remove the milliseconds so that I have
10/20/2014 10:34:06 AM
Do you know the best way to do this?
Thank you!
How about this?
select cast(col as timestamp(0))
EDIT:
The easiest way to avoid rounding is to use trunc() or to subtract half a second:
select cast(col - 0.5/(24*60*60) as timestamp(0))
try this
SELECT TO_CHAR(SYSDATE, 'MM-DD-YYYY HH24:MI:SS') "NOW"
FROM DUAL;
if you need 12-hour date format
SELECT TO_CHAR(SYSDATE, 'MM-DD-YYYY HH:MI:SS AM') "NOW"
FROM DUAL;
SQL FIDDLE
You can either cast it to a timestamp with no fractional seconds (this will round to the nearest second):
CAST( your_timestamp AS TIMESTAMP(0) )
Or to a DATE data type (this will truncate to the nearest second):
CAST( your_timestamp AS DATE )
If you want it as a TIMESTAMP(0) data type then cast it back:
CAST( CAST( your_timestamp AS DATE ) AS TIMESTAMP(0) )
Or you can convert it to a formatted string and specify the format model you want to use (this will truncate to the nearest second):
TO_CHAR( your_timestamp, 'YYYY-MM-DD HH24:MI:SS' )
Like this:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE your_table ( your_timestamp ) AS
SELECT TIMESTAMP '2017-10-25 12:53:12.10076' FROM DUAL;
Query 1:
SELECT CAST( your_timestamp AS TIMESTAMP(0) ) AS "Timestamp",
CAST( your_timestamp AS DATE ) AS "Date",
TO_CHAR( your_timestamp, 'DD-MM-YYYY HH24:MI:SS' ) AS "String"
FROM your_table
Results:
| Timestamp | Date | String |
|-----------------------|----------------------|---------------------|
| 2017-10-25 12:53:12.0 | 2017-10-25T12:53:12Z | 25-10-2017 12:53:12 |
note: How the TIMESTAMP and DATE are formatted in the output will depend on your NLS_TIMESTAMP_FORMAT and NLS_DATE_FORMAT session parameters but you can directly control the formatting of TO_CHAR when you specify a format model.
This might help!
select substr(to_char('10/20/2014 10:34:06.356000 AM'),1,instr(to_char('10/20/2014 10:34:06.356000 AM'),'.')-1)||' '||
substr(to_char('10/20/2014 10:34:06.356000 AM'),-2,instr(to_char('10/20/2014 10:34:06.356000 AM'),'.')-1) "Date"
from dual;