I want to convert date to number in oracle 11g .
The date is stored in (12/03/2013 12:23:00).
I want to convert this to Number(The date corresponding number value).
As in java we convert date to long .
I want the same to be done here .
Calendar c = Calendar.getInstance();
c.set(2013, 05, 23, 0, 0, 0);
Date date = c.getTime();
System.out.println("Date is " + date);
long longDate = date.getTime();
System.out.println("Date as long :" + longDate);
Date d = new Date(longDate);
System.out.println("Converted Date :" + d);*
The Output is :
**Date is Sun Jun 23 00:00:00 SGT 2013
Date as long :1371916800981
Converted Date :Sun Jun 23 00:00:00 SGT 2013**
Now I want to store value as 1371916800981
I am guessing that the long data type that you want is something like the number of seconds or milliseconds since 1970-01-01.
To get this requires just a bit of arithmetic:
select (to_date(s1, 'MM/DD/YYYY HH24:MI:SS') -
to_date('1970-01-01', 'YYYY-MM-DD')
) *24*60*60
from (select '12/03/2013 12:23:00' as s1 from dual
) t
I note that your result is using the current time stamp. This might include milliseconds which this constant date format doesn't include.
You can achieve this with a help of RAW data type:
SELECT
s1,
to_number(TO_CHAR(s1,'YYYYMMDDHH24MISS')) as s2,
utl_raw.cast_to_raw(s1) as d1,
utl_raw.cast_to_raw(s2) as d2,
round(utl_raw.cast_to_number(utl_raw.cast_to_raw(s1)),20) as s1,
round(utl_raw.cast_to_number(utl_raw.cast_to_raw(s2)),20) as s2,
utl_raw.cast_to_number(utl_raw.cast_to_raw(s1)) - utl_raw.cast_to_number(utl_raw.cast_to_raw(s2)) as s1_s2_diff
FROM
( select
sysdate as s1,
sysdate-1/24/60/60 as s2
from dual );
Output:
S1 S2
------------------- --------------
2014.03.16 11:14:16 20140316111416
D1 D2
-------------------------------------- --------------------------------------
323031342E30332E31362031313A31343A3136 323031342E30332E31362031313A31343A3135
S1_1 S2_1
-------------------------------------- --------------------------------------
-53524955535055524769525243,5249435247 -53524955535055524769525243,5249435248
SDIFF
------------
0,0000000001
Related
I have this sheet here set in a tab named Reports:
As can be seen, column A contains the date and time of the report. The most recent has been set on February 16th and the oldest is January 28th.
I would like to query the last 10 days, starting from today in another tab. So, if today is February 17th, I need all the reportes queried until February 7th.
Note: I don't need the last 10 reports, I need the last 10 days, no matter how many is accumulated.
I tried something like this:
=QUERY(SORT({
'Reports'!A1:A;
}, 1, 0),
"where Col2 is not null limit 10", 0)
Here is the sheet:
https://docs.google.com/spreadsheets/d/1w7beVyUr0pEUoRSgqQYYOi0y0Sbd8scC3B825GKA3sQ/edit?usp=sharing
Try this:
=QUERY({Report!A1:B} ; "SELECT *
WHERE Col2 is not null AND Col1 >= date '"
& TEXT(NOW()-10; "yyyy-MM-dd") & "' ")
try:
=QUERY({Report!A1:B};
"where Col1 >= date '"&TEXT(TODAY()-10; "yyyy-mm-dd")&"'
and Col1 <= date '"&TEXT(TODAY(); "yyyy-mm-dd")&"'"; 0)
or from Control sheet:
=ARRAYFORMULA(QUERY({IFNA(IF(N(Control!A2:A)<>0; Control!A2:A; DATE(
REGEXEXTRACT(Control!A2:A; "/(\d+) ");
REGEXEXTRACT(Control!A2:A; "/(\d+)/");
REGEXEXTRACT(Control!A2:A; "^\d+"))+
INDEX(SPLIT(Control!A2:A; " ");;2)))\ Control!B2:B};
"where Col1 >= "&DATEVALUE(TODAY()-10)&"
and Col1 <= "&DATEVALUE(TODAY())&"
format Col1 'mm/dd/yyyy hh:MM:ss'"; 0))
Unable to retrieve records properly with the formatted date values, need select query with right date format to get all records inserted per day
I have a date string like this in my script -
dateString :='26-MAR-20 05.00.00.00000000 AM';
I want to add 0.313 minutes to this date value. And also I want to
increment it to the next day something like this- '27-MAR-20
05.00.00.00000000 AM';
I tried this
dateString :='26-MAR-20 05.00.00.00000000 AM';
dateString :=to_char(dateField,'DD-MON-YYYY HH24:MI:SS.FF');
dateField := to_timestamp(dateString, 'DD/MON/YYYY HH24:MI:SS.FF') + 0.313 * INTERVAL '1' MINUTE;
I can see the output and inserted these values into the DB but
unable to retrieve records properly with these formatted date values..
I suspect it might be to do with the timestamp fields
When I run this query -
select *from rptallexceptions where exceptiontime between '27-MAR-2020 04.00.00.000000000 AM' and '28-MAR-2020 03.59.00.000000000 AM' order by exceptiontime desc;
--- this one gives 3833 records but expected is 4600
it shows only the records on 27th march., records inserted with timestamp containing 28th march are not retrieved..
select *from rptallexceptions where exceptiontime between '28-MAR-2020 04.00.00.000000000 AM' and '29-MAR-2020 03.59.00.000000000 AM' order by exceptiontime desc;
--- this one returns '0' rows
Excerpt from the script:
cnt :=cnt +1;
dateString :=to_char(dateField,'DD-MON-YYYY HH24:MI:SS.FF');
-- add time difference for each exception.
dateField := to_timestamp(dateString, 'DD/MON/YYYY HH24:MI:SS.FF') + 0.313 * INTERVAL '1' MINUTE;
-- after n*4600 exceptions,update date to next date.
IF REMAINDER(cnt,exceptionsPerDay) = 0 THEN
dateField := to_timestamp(dateField + 1,'DD/MON/YYYY HH24:MI:SS.FF');
END IF;
The way I see it, your problem is that you're comparing timestamps to strings.
Sample table:
SQL> create table test as
2 select to_timestamp('27.03.2020 04:00:00:000000', 'dd.mm.yyyy hh24:mi:ss:ff6') datum, 'A' name from dual
3 union all
4 select to_timestamp('28.03.2020 15:23:00:000000', 'dd.mm.yyyy hh24:mi:ss:ff6') datum, 'A' name from dual;
Table created.
Query should use timestamp, not string:
SQL> select *
2 from test
3 where datum between to_timestamp('25.03.2020 12:00:00:000000am', 'dd.mm.yyyy hh:mi:ss:ff6am') --> timestamp
4 and to_timestamp('28.03.2020 12:00:00:000000am', 'dd.mm.yyyy hh:mi:ss:ff6am'); --> timestamp
DATUM N
--------------------------------------------------------------------------- -
27.03.20 04:00:00,000000000 A
SQL>
You were kind of "lucky" (though, one might call it bad luck as your query didn't fail, but it produced wrong results, according to number of rows being returned) for not getting an error as my database raises (due to different NLS settings):
SQL> select *
2 from test
3 where datum between '25.03.2020 12:00:00:000000am' --> string
4 and '28.03.2020 12:00:00:000000am'; --> string
where datum between '25.03.2020 12:00:00:000000am'
*
ERROR at line 3:
ORA-01830: date format picture ends before converting entire input string
SQL>
Strings are handled differently than dates (or timestamps), or numbers. Maybe you'll see the difference clearly in this example:
SQL> with test (col) as
2 (select '1' from dual union all
3 select '9' from dual union all
4 select '20' from dual
5 )
6 select *
7 from test
8 where col < '9';
CO
--
1
20
SQL>
20 < 9? Yes, if those are strings. The same might have happened to you. Try with proper datatype.
When you do:
dateString :=to_char(dateField,'DD-MON-YYYY HH24:MI:SS.FF');
you are converting whatever is the initial value of dateField to a string; but it looks like that has has not been set yet, so you end up with an empty string (which is the same as null). Your original value of dateString is never being used.
If you skip that and just do:
dateString :='26-MAR-20 05.00.00.00000000 AM';
dateField := to_timestamp(dateString, 'DD/MON/YYYY HH24:MI:SS.FF') + 0.313 * INTERVAL '1' MINUTE;
then you are converting the 2-digit year 20 with a YYYY format element, which will turn it into year 0020, not 2020; but you also don't have AM in the format model, so it will get ORA-01830 anyway, and have HH24 instead of HH. I think your to_char() is attempting to 'correct' the string format, but that's not a great approach.
If you can't control the starting string format then the model has to match that:
dateString :='26-MAR-20 05.00.00.00000000 AM';
dateField := to_timestamp(dateString, 'DD-MON-RR HH:MI:SS.FF AM') + 0.313 * INTERVAL '1' MINUTE;
which gives dateField a value of 2020-03-26 05:00:18.780000.
Later on you do:
dateField := to_timestamp(dateField + 1,'DD/MON/YYYY HH24:MI:SS.FF');
which is also doing an implicit conversion of dateField + 1 - which is converted to a date, incidentally as timestamp + number is a date, not a timestamp - to a string; which will use your NLS_DATE_FORMAT. Presumably that is something like 'DD-MON-YYYY'.
So stepping through that:
dateField + 1 => date '2020-03-27 05:00:18' (losing fractional seconds)
implicit to_char(dateField + 1) => string '27-Mar-2020' (losing time)
to_timestamp(to_char(dateField + 1), '...') => timestamp '2020-03-27 00:00:00.000000' (with time at midnight).
So your between is, at best going to find records between 2020-03-26 05:00:18.780000 and 2020-03-27 00:00:00.0000000 - so it won't pick up any records later than midnight on the 27th.
Don't convert to and from strings when you don't need to; leave data in its native data type (timestamp in this case) and use direct manipulation with intervals.
Using between isn't ideal anyway, because it is inclusive; it would be better to end up with:
exceptiontime >= timestamp '2020-03-26 05:00:18.780000'
and exceptionTime < timestamp '2020-03-27 05:00:18.780000'
In storing my date in a derby table as "Apr 5 2017" (alpha + numeric) , will the query code here know how to query properly? As opposed to an all numeric format "04 05 2017". In other words, Can the query handle charvar for month sorting?
(PreparedStatement st = con.prepareStatement("select * from TEST5 where startCol >= date1 and endCol <= date2" );
ResultSet rs = st.executeQuery()) {
MainDisplay.jTable1.setModel(DbUtils.resultSetToTableModel(rs));
rs.close();
st.close();
con.close();
No, if you store the date in the db as a string like this the sorting will just be a string compare and the order will not be correct (how is Derby supposed to know this is a date?).
You should define the column type as being a DATE if you want it to hold a date or TIMESTAMP for a date + time.
I am having an issue trying to convert multiple dates to one defined format. We are receiving the multiple dates from another DB source so I do not have control of the formatting until it reaches ours.
Here are all the formats:
YYYYMMDD
YYYY-MM-DD HH:MM:SS
MM/DD/YYYY
MM-DD-YYYY
Abrieviated Day Month DD HH:MM:SS TimeZone YYYY ('Thu Feb 02 20:49:59 MSK 2012')
Fully written Day, Month DD, YYYY HH:MM:SS AM/PM
My requirement is to set them all to the standard MM/DD/YYYY format or null. Any ideas?
Thank you.
You may define a transformation function, basically processing sequentially each format:
create or replace function translate_date(i_date_string VARCHAR2) return date as
begin
-- you may optimize to not to go in all blocks based on the string format
-- order the blocks on the expected frequency
begin
return to_date(i_date_string,'yyyymmdd');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'yyyy/mm/dd');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'yyyy-mm-dd');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'yyyy-mm-dd hh24:mi:ss');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
-- transform to local timestamp and than to date
return cast(cast(to_timestamp_tz(i_date_string,'dy month dd hh24:mi:ss tzr yyyy') as TIMESTAMP WITH LOCAL TIME ZONE) as date);
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'dy, month dd, yyyy hh:mi:ss am');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
return NULL;
end;
/
for example for sample data
TSTMP
------------------------
20150101
2015-01-01 23:59:59
2015/01/01
2015-01-01
Thu Feb 02 20:49:59 Europe/Moscow 2012
Thu, Feb 02, 2012 10:49:59 AM
Thu, Feb 02, 2012 10:49:59 PM
you get
TSTMP RESULT_DATE
------------------------------------------ -------------------
20150101 01.01.2015 00:00:00
2015-01-01 23:59:59 01.01.2015 23:59:59
2015/01/01 01.01.2015 00:00:00
2015-01-01 01.01.2015 00:00:00
Thu Feb 02 20:49:59 Europe/Moscow 2012 02.02.2012 17:49:59
Thu, Feb 02, 2012 10:49:59 AM 02.02.2012 10:49:59
Thu, Feb 02, 2012 10:49:59 PM 02.02.2012 22:49:59
Note that I skipped the case with time zone abbraviation (MSK), see possible solution in the answer from #Sentinel, but check Conversion of String with Abbreviated Timezone to Timestamp that this may be ambiguous.
I'd suggest using a case statement with regexp_like conditions to detect likely formats and return dates using the appropriate date mask in the then clauses e.g.:
with tz as (
SELECT distinct tzabbrev
, first_value(min(tzname)) over (partition by tzabbrev order by count(*) desc) tzname
FROM v$timezone_names
group by tzabbrev
, TZ_OFFSET(tzname)
), dta as (
select yt.install_date
, regexp_replace(yt.install_date,tzabbrev,tzname,1,1,'i') install_date2
from your_table yt
left join tz
on regexp_like(install_date, tz.TZABBREV,'i')
)
select install_date, install_date2
, to_timestamp_tz( install_date2
, case
when regexp_like(install_date2,'^[A-Z]{3,} [A-Z]{3,} [0-9]{1,2} [0-9]{1,2}(:[0-9]{2}){1,2} [[:print:]]{5,} [0-9]{2,4}','i') then 'DY MON DD HH24:MI:SS TZR YYYY'
when regexp_like(install_date2,'^[A-Z]{4,},? [A-Z]{3,},? [0-9]{1,2},? [0-9]{2,4}','i') then 'DAY MONTH DD YYYY'
when regexp_like(install_date2,'^[A-Z]{3},? [A-Z]{3,},? [0-9]{1,2},? [0-9]{2,4}','i') then 'DY MONTH DD YYYY'
when regexp_like(install_date2,'^[0-9]{1,2}[-/][0-9]{1,2}[-/]([0-9]{2}){1,2}') then 'MM-DD-RRRR'
when regexp_like(install_date2,'^[0-9]{1,2}[-/ ][A-Z]{3,}[-/ ]([0-9]{2}){1,2}','i') then 'DD-MON-RRRR'
when regexp_like(install_date2,'^[A-Z]{3,}[-/ ][0-9]{1,2},?[-/ ]([0-9]{2}){1,2}','i') then 'MON-DD-RRRR'
when regexp_like(install_date2,'^(19|20)[0-9]{6}') then 'RRRRMMDD'
when regexp_like(install_date2,'^[23][0-9]{5}') then 'DDMMRR'
when regexp_like(install_date2,'^[0-9]{6}') then 'MMDDRR'
when regexp_like(install_date2,'^[01][0-9]{7}') then 'MMDDRRRR'
when regexp_like(install_date2,'^[23][0-9]{7}') then 'DDMMRRRR'
ELSE NULL
end
||case
when regexp_like(install_date2, '[0-9]{1,2}(:[0-9]{2}){1,2}$') then ' HH24:MI:SS'
when regexp_like(install_date2, '[0-9]{1,2}(:[0-9]{2}){1,2} ?(am|pm)$','i') then ' HH:MI:SS AM'
else null
end
)
Install_Time_Stamp
from dta;
I had issues with the time zone abbreviations so I added a step to replace them with time zone regions first.
The function can be simplified a little bit as to_date tolerates minor deviations (different separators, missing separators, missing time components, 2/4-digit year). For instance to_date(:str,'rrrr-mm-dd hh24:mi:ss') will cover
2020/09/18 01.02
2020.09.18 01
20200918010203
2020-0901
202009-01
20/09/18
To_timestamp_tz will also tolerate missing milliseconds and time zone (including missing TZ elements TZM and TZD).
So we basically need to take care of major variations only like hh24/hh, mm/mon, elements order, "T" separator in ISO 8601 (2020-01-01T01:02:03), TZ designators (UTC offset TZH:TZM / region name TZR), and day of week (DY).
I'm having date as 41293 in oracle, how can i show it in DD/MON/YYYY format?
If i copy pasted it in Excel and change it to date format, it shows 01/19/13
Please help me.
The value you have is the number of days since the 30th of December 1899. Try:
select to_char(
to_date('1899-12-30', 'YYYY-MM-DD') + 41293,
'DD/MON/YYYY') from dual
Quoting from Oracle forum:
You need a tool to do that, since format is to tell oracle what type of format you have on your date type in the spreadsheet. While you may not have opted to format the date in Excel, it will appear as a date in the previewer. Use the format from this as a guide to enter into the datatype panel.
so, if you have a date that looks like this in the previewer, 19-jan-2006, then your format for the data type panel if you choose to insert that column is going to be DD-MON-YYYY,
Option 1:
Try using the below functions
FUNCTION FROMEXCELDATETIME ( ACELLVALUE IN VARCHAR2 )
RETURN TIMESTAMP
IS
EXCEL_BASE_DATE_TIME CONSTANT TIMESTAMP
:= TO_TIMESTAMP ( '12/31/1899',
'mm/dd/yyyy' ) ;
VAL CONSTANT NUMBER
:= TO_NUMBER ( NULLIF ( TRIM ( ACELLVALUE ),
'0' ) ) ;
BEGIN
RETURN EXCEL_BASE_DATE_TIME
+ NUMTODSINTERVAL ( VAL
- CASE
WHEN VAL >= 60
THEN
1
ELSE
0
END,
'DAY' );
END;
FUNCTION TOEXCELDATETIME ( ATIMESTAMP IN TIMESTAMP )
RETURN VARCHAR2
IS
EXCEL_BASE_DATE_TIME CONSTANT TIMESTAMP
:= TO_TIMESTAMP ( '12/31/1899',
'mm/dd/yyyy' ) ;
DIF CONSTANT INTERVAL DAY ( 9 ) TO SECOND ( 9 )
:= ATIMESTAMP
- EXCEL_BASE_DATE_TIME ;
DAYS CONSTANT INTEGER := EXTRACT ( DAY FROM DIF );
BEGIN
RETURN CASE
WHEN DIF IS NULL
THEN
''
ELSE
TO_CHAR ( DAYS
+ CASE
WHEN DAYS >= 60
THEN
1
ELSE
0
END
+ ROUND ( ( EXTRACT ( HOUR FROM DIF )
+ ( EXTRACT ( MINUTE FROM DIF )
+ EXTRACT ( SECOND FROM DIF )
/ 60 )
/ 60 )
/ 24,
4 ) )
END;
END;
Option 2:
The excel function would be =TEXT(B2,"MM/DD/YY"), to convert an Excel date value stored in B2. Then try using the test character in Oracle
If considering 1900 Jan 1st as start date,
SELECT
TO_CHAR ( TO_DATE ( '1900-01-01',
'YYYY-MM-DD' )
+ 41293,
'DD/MON/YYYY' )
FROM
DUAL
Microsoft's Documentation
Excel stores dates as sequential serial numbers so that they can be used in calculations. January 1, 1900 is serial number 1, and January 1, 2008 is serial number 39448 because it is 39,447 days after January 1, 1900.
Excel has a bug feature where it considers 1900 to be a leap year and day 60 is 1900-02-29 but that day never existed and a correction needs to be applied for this erroneous day.
It does also state that:
Microsoft Excel correctly handles all other leap years, including century years that are not leap years (for example, 2100). Only the year 1900 is incorrectly handled.
Therefore only a single correction is required.
So:
Before 1900-03-01 you can use DATE '1899-12-31' + value.
On or after 1900-03-01 you can use DATE '1899-12-30' + value.
Which can be put into a CASE statement:
SELECT CASE
WHEN value >= 1 AND value < 60
THEN DATE '1899-12-31' + value
WHEN value >= 60 AND value < 61
THEN NULL
WHEN value >= 61
THEN DATE '1899-12-30' + value
END AS converted_date
FROM your_table