Set the session date format
alter session set nls_date_format = 'DD-MON-YYYY HH24:MI'
Statement processed.
Datetime literals
select date'2023-01-17' date_literal,
timestamp'2023-01-17 14:00:00.123456789' ts_literal,
timestamp'2023-01-17 14:00:00 Europe/London' tstz_literal
from dual
DATE_LITERAL | TS_LITERAL | TSTZ_LITERAL | 17-JAN-2023 00:00 | 17-JAN-23 02.00.00.123457 PM | 17-JAN-23 02.00.00.000000 PM EUROPE/LONDON |
---|
A quick note on TRUNC
select sysdate full_datetime,
trunc ( sysdate, 'HH24' ) to_hour_start,
trunc ( sysdate ) to_day_start,
trunc ( sysdate, 'YYYY' ) to_year_start
from dual
FULL_DATETIME | TO_HOUR_START | TO_DAY_START | TO_YEAR_START | 17-JAN-2023 11:29 | 17-JAN-2023 11:00 | 17-JAN-2023 00:00 | 01-JAN-2023 00:00 |
---|
alter session set nls_date_format = 'DD-MON-YYYY'
Statement processed.
Implicit conversion
select count(*) from hr.employees
where hire_date >= '01-JAN-2005'
COUNT(*) | 83 |
---|
alter session set nls_date_format = 'YYYYMMDD'
Statement processed.
Implicit conversion
select count(*) from hr.employees
where hire_date >= '01-JAN-2005'
ORA-01858: a non-numeric character was found where a numeric was expectedMore Details: https://docs.oracle.com/error-help/db/ora-01858
Explicit conversion
select count(*) from hr.employees
where hire_date >= to_date (
'01-JAN-2005', 'DD-MON-YYYY'
)
COUNT(*) | 83 |
---|
Avoid TO_DATE on DATE values!
select * from hr.employees
where hire_date >= to_date (
sysdate, 'DD-MON-YYYY'
)
ORA-01861: literal does not match format stringMore Details: https://docs.oracle.com/error-help/db/ora-01861
alter session set nls_date_format = ' "DT" DD-MON-YYYY HH24:MI '
Statement processed.
alter session set nls_timestamp_format = ' "TS" DD-MON-YYYY HH24:MI '
Statement processed.
alter session set nls_timestamp_tz_format = ' "TSTZ" DD-MON-YYYY HH24:MI TZH:TZM '
Statement processed.
View the current NLS settings
select * from nls_session_parameters
where parameter like '%DATE%' or parameter like '%TIMESTAMP%'
PARAMETER | VALUE | NLS_DATE_FORMAT | "DT" DD-MON-YYYY HH24:MI | NLS_DATE_LANGUAGE | AMERICAN | NLS_TIMESTAMP_FORMAT | "TS" DD-MON-YYYY HH24:MI | NLS_TIMESTAMP_TZ_FORMAT | "TSTZ" DD-MON-YYYY HH24:MI TZH:TZM |
---|
alter session set nls_date_language = 'Spanish'
Statement processed.
Language conversion errors
select * from hr.employees
where hire_date >= to_date (
'01-JAN-2005', 'DD-MON-YYYY'
)
ORA-01843: not a valid monthMore Details: https://docs.oracle.com/error-help/db/ora-01843
select sysdate from dual
SYSDATE | DT 17-ENE-2023 11:29 |
---|
Full explicit conversion
select count(*) from hr.employees
where hire_date >= to_date (
'01-JAN-2005', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE = English'
)
COUNT(*) | 83 |
---|
alter session set nls_date_language = 'English'
Statement processed.
Handling data in unexpected/unwanted formats
select to_date (
'01-JAN-2005'
default '99991231' on conversion error,
'YYYYMMDD'
)
from dual
TO_DATE('01-JAN-2005'DEFAULT'99991231'ONCONVERSIONERROR,'YYYYMMDD') | DT 31-DEC-9999 00:00 |
---|
select to_date (
'01-JAN-2005'
default '31-DEC-9999' on conversion error,
'YYYYMMDD'
)
from dual
ORA-01858: a non-numeric character was found where a numeric was expectedMore Details: https://docs.oracle.com/error-help/db/ora-01858
Test data type conversions
create or replace function string_to_date (
date_string varchar2
) return date as
return_date date;
begin
return_date := case
when validate_conversion ( date_string as date, 'DD-MON-YYYY' ) = 1
then
to_date ( date_string, 'DD-MON-YYYY' )
when validate_conversion ( date_string as date, 'YYYYMMDD' ) = 1
then
to_date ( date_string, 'YYYYMMDD' )
when validate_conversion ( date_string as date, 'MMDDYYYY' ) = 1
then
to_date ( date_string, 'MMDDYYYY' )
end;
if return_date is null then
raise_application_error ( -20001, 'Date in unhandled format' );
end if;
return return_date;
end;
Function created.
Examples using the multiformat converter
select '01-JAN-2005', count(*) from hr.employees
where hire_date >= string_to_date ( '01-JAN-2005' )
'01-JAN-2005' | COUNT(*) | 01-JAN-2005 | 83 |
---|
select '20050101', count(*) from hr.employees
where hire_date >= string_to_date ( '20050101' )
'20050101' | COUNT(*) | 20050101 | 83 |
---|
Flexible format masks
with rws ( date_string ) as (
select '17-January-23' from dual union all
select '17~January~2023' from dual union all
select '17-Jan-2023' from dual union all
select '17012023' from dual
)
select date_string, to_date (
date_string default null on conversion error,
'DD-MM-YYYY'
) dt
from rws
DATE_STRING | DT | 17-January-23 | DT 17-JAN-0023 00:00 | 17~January~2023 | DT 17-JAN-2023 00:00 | 17-Jan-2023 | DT 17-JAN-2023 00:00 | 17012023 | DT 17-JAN-2023 00:00 |
---|
Exact format matching
with rws ( date_string ) as (
select '17-January-23' from dual union all
select '17~January~2023' from dual union all
select '17-Jan-2023' from dual union all
select '17012023' from dual
)
select date_string ,
to_date (
date_string default null on conversion error ,
'FXDD-MM-YYYY'
) exact_match
from rws
DATE_STRING | EXACT_MATCH | 17-January-23 | - | 17~January~2023 | - | 17-Jan-2023 | - | 17012023 | - |
---|
Date to string conversions
select hire_date nls_session_date,
to_char ( hire_date, 'IYYY-IW' ) iso_year_week,
to_char ( hire_date, 'DY ddth Month YEAR' ) spell_date,
to_char ( hire_date, 'j RM w"w" q"q"' ) julian_dy__roman_mnth__mnth_week__qtr
from hr.employees
fetch first 10 rows only
NLS_SESSION_DATE | ISO_YEAR_WEEK | SPELL_DATE | JULIAN_DY__ROMAN_MNTH__MNTH_WEEK__QTR | DT 17-JUN-2003 00:00 | 2003-25 | TUE 17th June TWO THOUSAND THREE | 2452808 VI 3w 2q | DT 21-SEP-2005 00:00 | 2005-38 | WED 21st September TWO THOUSAND FIVE | 2453635 IX 3w 3q | DT 13-JAN-2001 00:00 | 2001-02 | SAT 13th January TWO THOUSAND ONE | 2451923 I 2w 1q | DT 03-JAN-2006 00:00 | 2006-01 | TUE 03rd January TWO THOUSAND SIX | 2453739 I 1w 1q | DT 21-MAY-2007 00:00 | 2007-21 | MON 21st May TWO THOUSAND SEVEN | 2454242 V 3w 2q | DT 25-JUN-2005 00:00 | 2005-25 | SAT 25th June TWO THOUSAND FIVE | 2453547 VI 4w 2q | DT 05-FEB-2006 00:00 | 2006-05 | SUN 05th February TWO THOUSAND SIX | 2453772 II 1w 1q | DT 07-FEB-2007 00:00 | 2007-06 | WED 07th February TWO THOUSAND SEVEN | 2454139 II 1w 1q | DT 17-AUG-2002 00:00 | 2002-33 | SAT 17th August TWO THOUSAND TWO | 2452504 VIII 3w 3q | DT 16-AUG-2002 00:00 | 2002-33 | FRI 16th August TWO THOUSAND TWO | 2452503 VIII 3w 3q |
---|
Date to string conversions
select to_char ( sysdate, 'hh24:mi:ss' ) hour_min_sec,
to_char ( sysdate, 'sssss' ) seconds_in_day,
to_char ( systimestamp, 'FF' ) fractional_seconds,
to_char ( systimestamp, 'tzr tzh:tzm' ) time_zone
from dual
HOUR_MIN_SEC | SECONDS_IN_DAY | FRACTIONAL_SECONDS | TIME_ZONE | 11:29:21 | 41361 | 522534 | +00:00 +00:00 |
---|
DATE <> TIMESTAMP conversion
select cast ( sysdate as timestamp ) ts,
/* Implicit session time zone */
cast ( sysdate as timestamp with time zone ) tstz,
/* Lose any fractional seconds and time zone */
cast ( systimestamp as date ) dt
from dual
TS | TSTZ | DT | TS 17-JAN-2023 11:29 | TSTZ 17-JAN-2023 11:29 -08:00 | DT 17-JAN-2023 11:29 |
---|
Interval literals
select interval '1' day,
interval '12:34:56.123456789' hour to second(9),
interval '99-1' year(9) to month
from dual
INTERVAL'1'DAY | INTERVAL'12:34:56.123456789'HOURTOSECOND(9) | INTERVAL'99-1'YEAR(9)TOMONTH | +01 00:00:00 | +00 12:34:56.123456789 | +000000099-01 |
---|
String to interval conversions
select to_dsinterval ( '01 00:00:00' ) one_day_sql,
to_dsinterval ( 'P1D' ) one_day_iso,
--
to_dsinterval ( '00 12:34:56.789' ) hr_mi_s_sql,
to_dsinterval ( 'PT12H34M56.789S' ) hr_mi_s_iso,
--
to_yminterval ( '99-1' ) yr_mth_sql,
to_yminterval ( 'P99Y1M' ) yr_mth_iso
from dual
ONE_DAY_SQL | ONE_DAY_ISO | HR_MI_S_SQL | HR_MI_S_ISO | YR_MTH_SQL | YR_MTH_ISO | +000000001 00:00:00.000000000 | +000000001 00:00:00.000000000 | +000000000 12:34:56.789000000 | +000000000 12:34:56.789000000 | +000000099-01 | +000000099-01 |
---|
Convert numbers to intervals
select numtodsinterval ( 1, 'day' ) one_day,
numtodsinterval ( 86400, 'second' ) one_day_in_s,
--
numtodsinterval ( 12, 'hour' )
+ numtodsinterval ( 34, 'minute' )
+ numtodsinterval ( 56, 'second' ) time_hms,
numtodsinterval ( 45296/86400, 'day' ) time_in_day,
--
numtoyminterval ( 1189, 'month' ) ym_in_months,
numtoyminterval ( 99.0833, 'year' ) ym_in_years
from dual
ONE_DAY | ONE_DAY_IN_S | TIME_HMS | TIME_IN_DAY | YM_IN_MONTHS | YM_IN_YEARS | +000000001 00:00:00.000000000 | +000000001 00:00:00.000000000 | +000000000 12:34:56.000000000 | +000000000 12:34:56.000000000 | +000000099-01 | +000000099-01 |
---|
Adding/subtracting durations
with vals as (
select date'2023-01-01' start_date,
timestamp'2023-01-01 00:00:00' start_timestamp
from dual
), rws as (
select start_date + ( level / 6 ) dt_plus_number,
start_date + numtodsinterval ( level / 6, 'day' ) dt_plus_interval,
start_timestamp + ( level / 6 ) ts_plus_number,
start_timestamp + numtodsinterval ( level / 6, 'day' ) ts_plus_interval
from vals
connect by level <= 10
)
select * from rws
DT_PLUS_NUMBER | DT_PLUS_INTERVAL | TS_PLUS_NUMBER | TS_PLUS_INTERVAL | DT 01-JAN-2023 04:00 | DT 01-JAN-2023 04:00 | DT 01-JAN-2023 04:00 | TS 01-JAN-2023 04:00 | DT 01-JAN-2023 08:00 | DT 01-JAN-2023 08:00 | DT 01-JAN-2023 08:00 | TS 01-JAN-2023 08:00 | DT 01-JAN-2023 12:00 | DT 01-JAN-2023 12:00 | DT 01-JAN-2023 12:00 | TS 01-JAN-2023 12:00 | DT 01-JAN-2023 16:00 | DT 01-JAN-2023 16:00 | DT 01-JAN-2023 16:00 | TS 01-JAN-2023 16:00 | DT 01-JAN-2023 20:00 | DT 01-JAN-2023 20:00 | DT 01-JAN-2023 20:00 | TS 01-JAN-2023 20:00 | DT 02-JAN-2023 00:00 | DT 02-JAN-2023 00:00 | DT 02-JAN-2023 00:00 | TS 02-JAN-2023 00:00 | DT 02-JAN-2023 04:00 | DT 02-JAN-2023 04:00 | DT 02-JAN-2023 04:00 | TS 02-JAN-2023 04:00 | DT 02-JAN-2023 08:00 | DT 02-JAN-2023 08:00 | DT 02-JAN-2023 08:00 | TS 02-JAN-2023 08:00 | DT 02-JAN-2023 12:00 | DT 02-JAN-2023 12:00 | DT 02-JAN-2023 12:00 | TS 02-JAN-2023 12:00 | DT 02-JAN-2023 16:00 | DT 02-JAN-2023 16:00 | DT 02-JAN-2023 16:00 | TS 02-JAN-2023 16:00 |
---|
Subtracting datetimes
with vals as (
select date'2023-01-01' start_date,
timestamp'2023-01-01 00:00:00' start_timestamp
from dual
), rws as (
select start_date, start_timestamp,
start_date + ( level / 6 ) dt,
start_timestamp + numtodsinterval ( level / 6, 'day' ) ts
from vals
connect by level <= 10
)
select dt - start_date,
dt - start_timestamp,
ts - start_timestamp,
ts - start_date
from rws
DT-START_DATE | DT-START_TIMESTAMP | TS-START_TIMESTAMP | TS-START_DATE | .1666666666666666666666666666666666666667 | +000000000 04:00:00.000000000 | +000000000 04:00:00.000000000 | +000000000 04:00:00.000000000 | .3333333333333333333333333333333333333333 | +000000000 08:00:00.000000000 | +000000000 08:00:00.000000000 | +000000000 08:00:00.000000000 | .5 | +000000000 12:00:00.000000000 | +000000000 12:00:00.000000000 | +000000000 12:00:00.000000000 | .6666666666666666666666666666666666666667 | +000000000 16:00:00.000000000 | +000000000 16:00:00.000000000 | +000000000 16:00:00.000000000 | .8333333333333333333333333333333333333333 | +000000000 20:00:00.000000000 | +000000000 20:00:00.000000000 | +000000000 20:00:00.000000000 | 1 | +000000001 00:00:00.000000000 | +000000001 00:00:00.000000000 | +000000001 00:00:00.000000000 | 1.16666666666666666666666666666666666667 | +000000001 04:00:00.000000000 | +000000001 04:00:00.000000000 | +000000001 04:00:00.000000000 | 1.33333333333333333333333333333333333333 | +000000001 08:00:00.000000000 | +000000001 08:00:00.000000000 | +000000001 08:00:00.000000000 | 1.5 | +000000001 12:00:00.000000000 | +000000001 12:00:00.000000000 | +000000001 12:00:00.000000000 | 1.66666666666666666666666666666666666667 | +000000001 16:00:00.000000000 | +000000001 16:00:00.000000000 | +000000001 16:00:00.000000000 |
---|
Get duration difference in seconds (UNIX epoch)
select *
from (
select ( sysdate - date'1970-01-01' ) * 86400 dt_epoch,
systimestamp at time zone 'UTC' - timestamp'1970-01-01 00:00:00 UTC' epoch_dsi
from dual
) cross apply (
select extract ( day from epoch_dsi ) * 86400 +
extract ( hour from epoch_dsi ) * 3600 +
extract ( minute from epoch_dsi ) * 60 +
extract ( second from epoch_dsi ) ts_epoch
from dual
)
DT_EPOCH | EPOCH_DSI | TS_EPOCH | 1673954961.000000000000000000000000000002 | +000019374 11:29:21.667717000 | 1673954961.667717 |
---|
EXTRACT on DATE
select extract ( hour from sysdate ) from dual
ORA-30076: invalid extract field for extract sourceMore Details: https://docs.oracle.com/error-help/db/ora-30076
Months not a fixed duration!
select date'2023-01-01' + 31 jan_dt_plus_31,
date'2023-02-01' + 31 feb_dt_plus_31,
timestamp'2023-01-01 00:00:00' + interval '31' day jan_ts_plus_31,
timestamp'2023-02-01 00:00:00' + interval '31' day feb_ts_plus_31
from dual
JAN_DT_PLUS_31 | FEB_DT_PLUS_31 | JAN_TS_PLUS_31 | FEB_TS_PLUS_31 | DT 01-FEB-2023 00:00 | DT 04-MAR-2023 00:00 | TS 01-FEB-2023 00:00 | TS 04-MAR-2023 00:00 |
---|
Adding months
select add_months ( date'2023-01-01', 1 ) jan_dt_plus_1,
add_months ( date'2023-02-01', 1 ) feb_dt_plus_1,
timestamp'2023-01-01 00:00:00' + interval '1' month jan_ts_plus_1,
timestamp'2023-02-01 00:00:00' + interval '1' month feb_ts_plus_1
from dual
JAN_DT_PLUS_1 | FEB_DT_PLUS_1 | JAN_TS_PLUS_1 | FEB_TS_PLUS_1 | DT 01-FEB-2023 00:00 | DT 01-MAR-2023 00:00 | TS 01-FEB-2023 00:00 | TS 01-MAR-2023 00:00 |
---|
Month end logic
select add_months ( date'2023-01-31', 1 ) jan_dt_plus_1,
add_months ( date'2023-02-28', 1 ) feb_dt_plus_1
from dual
JAN_DT_PLUS_1 | FEB_DT_PLUS_1 | DT 28-FEB-2023 00:00 | DT 31-MAR-2023 00:00 |
---|
Month end logic for TIMESTAMP
select timestamp'2023-01-31 00:00:00' + interval '1' month
from dual
ORA-01839: date not valid for month specifiedMore Details: https://docs.oracle.com/error-help/db/ora-01839
ADD_MONTHS on TIMESTAMP
select add_months ( timestamp'2023-01-31 00:00:00', 1 )
from dual
ADD_MONTHS(TIMESTAMP'2023-01-3100:00:00',1) | DT 28-FEB-2023 00:00 |
---|
Add months to 28th of month
with rws as (
select add_months ( date'2023-01-28', level - 1 ) dt
from dual
connect by level <= 10
)
select * from rws
DT | DT 28-JAN-2023 00:00 | DT 28-FEB-2023 00:00 | DT 28-MAR-2023 00:00 | DT 28-APR-2023 00:00 | DT 28-MAY-2023 00:00 | DT 28-JUN-2023 00:00 | DT 28-JUL-2023 00:00 | DT 28-AUG-2023 00:00 | DT 28-SEP-2023 00:00 | DT 28-OCT-2023 00:00 |
---|
with rws as (
select add_months ( date'2023-02-28', level - 1 ) dt
from dual
connect by level <= 10
)
select * from rws
DT | DT 28-FEB-2023 00:00 | DT 31-MAR-2023 00:00 | DT 30-APR-2023 00:00 | DT 31-MAY-2023 00:00 | DT 30-JUN-2023 00:00 | DT 31-JUL-2023 00:00 | DT 31-AUG-2023 00:00 | DT 30-SEP-2023 00:00 | DT 31-OCT-2023 00:00 | DT 30-NOV-2023 00:00 |
---|
Add to end of month on DATE
with rws as (
select /* Get last day in month */
last_day (
/* Add months on */
add_months (
/* Get start of month */
trunc ( date'2023-01-31', 'mm' ),
level - 1
)
) dt
from dual
connect by level <= 10
)
select * from rws
DT | DT 31-JAN-2023 00:00 | DT 28-FEB-2023 00:00 | DT 31-MAR-2023 00:00 | DT 30-APR-2023 00:00 | DT 31-MAY-2023 00:00 | DT 30-JUN-2023 00:00 | DT 31-JUL-2023 00:00 | DT 31-AUG-2023 00:00 | DT 30-SEP-2023 00:00 | DT 31-OCT-2023 00:00 |
---|
select trunc ( systimestamp, 'mm' ),
last_day ( systimestamp )
from dual
TRUNC(SYSTIMESTAMP,'MM') | LAST_DAY(SYSTIMESTAMP) | DT 01-JAN-2023 00:00 | DT 31-JAN-2023 11:29 |
---|
Add to end of month TIMESTAMP
with rws as (
select /* 1st next month */
( timestamp'2023-01-31 00:00:00' + interval '1' day )
/* Add the months */
+ numtoyminterval ( level - 1, 'month' )
/* Subtract one day to go back to the end */
- interval '1' day
ts
from dual
connect by level <= 10
)
select * from rws
TS | TS 31-JAN-2023 00:00 | TS 28-FEB-2023 00:00 | TS 31-MAR-2023 00:00 | TS 30-APR-2023 00:00 | TS 31-MAY-2023 00:00 | TS 30-JUN-2023 00:00 | TS 31-JUL-2023 00:00 | TS 31-AUG-2023 00:00 | TS 30-SEP-2023 00:00 | TS 31-OCT-2023 00:00 |
---|
Check logic starting with 28th Feb
with rws as (
select last_day (
add_months (
trunc ( date'2023-02-28', 'mm' ),
level - 1
)
) dt,
( timestamp'2023-02-28 00:00:00' + interval '1' day )
+ numtoyminterval ( level - 1, 'month' )
- interval '1' day
ts
from dual
connect by level <= 10
)
select * from rws
DT | TS | DT 28-FEB-2023 00:00 | TS 28-FEB-2023 00:00 | DT 31-MAR-2023 00:00 | TS 31-MAR-2023 00:00 | DT 30-APR-2023 00:00 | TS 30-APR-2023 00:00 | DT 31-MAY-2023 00:00 | TS 31-MAY-2023 00:00 | DT 30-JUN-2023 00:00 | TS 30-JUN-2023 00:00 | DT 31-JUL-2023 00:00 | TS 31-JUL-2023 00:00 | DT 31-AUG-2023 00:00 | TS 31-AUG-2023 00:00 | DT 30-SEP-2023 00:00 | TS 30-SEP-2023 00:00 | DT 31-OCT-2023 00:00 | TS 31-OCT-2023 00:00 | DT 30-NOV-2023 00:00 | TS 30-NOV-2023 00:00 |
---|
Months between two DATEs
with vals as (
select date'2023-01-01' start_date
from dual
), rws as (
select start_date,
add_months ( start_date, level - 1 ) month_date
from vals
connect by level <= 10
)
select months_between ( month_date, start_date )
from rws
MONTHS_BETWEEN(MONTH_DATE,START_DATE) | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
MONTHS_BETWEEN uses 31 month days
with vals as (
select date'2023-01-01' start_date from dual
), rws as (
select start_date,
add_months ( start_date + 15, level - 1 ) month_date
from vals
connect by level <= 10
)
select month_date,
months_between ( month_date, start_date ) months,
15 / 31 fraction
from rws
MONTH_DATE | MONTHS | FRACTION | DT 16-JAN-2023 00:00 | .4838709677419354838709677419354838709677 | .4838709677419354838709677419354838709677 | DT 16-FEB-2023 00:00 | 1.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-MAR-2023 00:00 | 2.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-APR-2023 00:00 | 3.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-MAY-2023 00:00 | 4.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-JUN-2023 00:00 | 5.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-JUL-2023 00:00 | 6.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-AUG-2023 00:00 | 7.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-SEP-2023 00:00 | 8.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 | DT 16-OCT-2023 00:00 | 9.48387096774193548387096774193548387097 | .4838709677419354838709677419354838709677 |
---|
MONTHS_BETWEEN uses 31 month days
with vals as (
select date'2023-02-28' start_date
from dual
), rws as (
select start_date, start_date + level - 1 dt
from vals
connect by level <= 10
)
select dt,
months_between ( dt, start_date ),
months_between ( dt, start_date ) * 31 days_between
from rws
DT | MONTHS_BETWEEN(DT,START_DATE) | DAYS_BETWEEN | DT 28-FEB-2023 00:00 | 0 | 0 | DT 01-MAR-2023 00:00 | .1290322580645161290322580645161290322581 | 4 | DT 02-MAR-2023 00:00 | .1612903225806451612903225806451612903226 | 5 | DT 03-MAR-2023 00:00 | .1935483870967741935483870967741935483871 | 6 | DT 04-MAR-2023 00:00 | .2258064516129032258064516129032258064516 | 7 | DT 05-MAR-2023 00:00 | .2580645161290322580645161290322580645161 | 8 | DT 06-MAR-2023 00:00 | .2903225806451612903225806451612903225806 | 9 | DT 07-MAR-2023 00:00 | .3225806451612903225806451612903225806452 | 10 | DT 08-MAR-2023 00:00 | .3548387096774193548387096774193548387097 | 11 | DT 09-MAR-2023 00:00 | .3870967741935483870967741935483870967742 | 12 |
---|
Months between two TIMESTAMPs
with vals as (
select timestamp'2023-01-01 00:00:00' start_ts
from dual
), rws as (
select start_ts,
start_ts + numtoyminterval ( level - 1, 'month' ) start_month,
start_ts + numtoyminterval ( level - 1, 'month' ) + interval '14 23:59:59' day to second mid_month_15,
start_ts + numtoyminterval ( level - 1, 'month' ) + interval '15' day mid_month_16
from vals
connect by level <= 10
)
select start_month,
( start_month - start_ts ) year to month start_ym,
mid_month_15,
( mid_month_15 - start_ts ) year to month mid_15_ym,
mid_month_16,
( mid_month_16 - start_ts ) year to month mid_16_ym
from rws
START_MONTH | START_YM | MID_MONTH_15 | MID_15_YM | MID_MONTH_16 | MID_16_YM | TS 01-JAN-2023 00:00 | +00-00 | TS 15-JAN-2023 23:59 | +00-00 | TS 16-JAN-2023 00:00 | +00-01 | TS 01-FEB-2023 00:00 | +00-01 | TS 15-FEB-2023 23:59 | +00-01 | TS 16-FEB-2023 00:00 | +00-02 | TS 01-MAR-2023 00:00 | +00-02 | TS 15-MAR-2023 23:59 | +00-02 | TS 16-MAR-2023 00:00 | +00-03 | TS 01-APR-2023 00:00 | +00-03 | TS 15-APR-2023 23:59 | +00-03 | TS 16-APR-2023 00:00 | +00-04 | TS 01-MAY-2023 00:00 | +00-04 | TS 15-MAY-2023 23:59 | +00-04 | TS 16-MAY-2023 00:00 | +00-05 | TS 01-JUN-2023 00:00 | +00-05 | TS 15-JUN-2023 23:59 | +00-05 | TS 16-JUN-2023 00:00 | +00-06 | TS 01-JUL-2023 00:00 | +00-06 | TS 15-JUL-2023 23:59 | +00-06 | TS 16-JUL-2023 00:00 | +00-07 | TS 01-AUG-2023 00:00 | +00-07 | TS 15-AUG-2023 23:59 | +00-07 | TS 16-AUG-2023 00:00 | +00-08 | TS 01-SEP-2023 00:00 | +00-08 | TS 15-SEP-2023 23:59 | +00-08 | TS 16-SEP-2023 00:00 | +00-09 | TS 01-OCT-2023 00:00 | +00-09 | TS 15-OCT-2023 23:59 | +00-09 | TS 16-OCT-2023 00:00 | +00-10 |
---|
Adding intervals
select interval '1' day +
interval '1' hour +
interval '1' minute +
interval '1' second +
interval '0.1' second ds_int,
interval '1' year +
interval '1' month ym_int
from dual
DS_INT | YM_INT | +000000001 01:01:01.100000000 | +000000001-01 |
---|
Adding intervals - must be compatible
select interval '1' month + interval '1' day
from dual
ORA-30081: invalid data type for datetime/interval arithmeticMore Details: https://docs.oracle.com/error-help/db/ora-30081
Set the session time zone
alter session set time_zone = 'Europe/London'
Statement processed.
Current time
select sysdate, systimestamp, dbtimezone,
current_date, current_timestamp, sessiontimezone
from dual
SYSDATE | SYSTIMESTAMP | DBTIMEZONE | CURRENT_DATE | CURRENT_TIMESTAMP | SESSIONTIMEZONE | DT 17-JAN-2023 11:29 | TSTZ 17-JAN-2023 11:29 +00:00 | +00:00 | DT 17-JAN-2023 11:29 | TSTZ 17-JAN-2023 11:29 +00:00 | Europe/London |
---|
alter session set time_zone = 'Asia/Kolkata'
Statement processed.
select sysdate, systimestamp, dbtimezone,
current_date, current_timestamp, sessiontimezone
from dual
SYSDATE | SYSTIMESTAMP | DBTIMEZONE | CURRENT_DATE | CURRENT_TIMESTAMP | SESSIONTIMEZONE | DT 17-JAN-2023 11:29 | TSTZ 17-JAN-2023 11:29 +00:00 | +00:00 | DT 17-JAN-2023 16:59 | TSTZ 17-JAN-2023 16:59 +05:30 | Asia/Kolkata |
---|
alter session set time_zone = 'UTC'
Statement processed.
Storing time zone information
create table t (
id integer generated as identity,
sess_tz varchar2(128),
ts timestamp,
ts_tz timestamp with time zone,
ts_ltz timestamp with local time zone
)
Table created.
alter session set time_zone = 'Europe/London'
Statement processed.
Inserting into TIMESTAMPs
insert into t ( sess_tz, ts, ts_tz, ts_ltz )
with rws as (
select timestamp'2023-01-01 00:00:00' ts from dual union all
select timestamp'2023-09-01 00:00:00' ts from dual union all
select timestamp'2023-01-01 00:00:00 Asia/Kolkata' ts from dual union all
select timestamp'2023-09-01 00:00:00 Asia/Kolkata' ts from dual
)
select sessiontimezone, ts, ts, ts from rws
4 row(s) inserted.
alter session set time_zone = 'UTC'
Statement processed.
insert into t ( sess_tz, ts, ts_tz, ts_ltz )
with rws as (
select timestamp'2023-01-01 00:00:00' ts from dual union all
select timestamp'2023-09-01 00:00:00' ts from dual union all
select timestamp'2023-01-01 00:00:00 Asia/Kolkata' ts from dual union all
select timestamp'2023-09-01 00:00:00 Asia/Kolkata' ts from dual
)
select sessiontimezone, ts, ts, ts from rws
4 row(s) inserted.
alter session set time_zone = 'Asia/Kolkata'
Statement processed.
insert into t ( sess_tz, ts, ts_tz, ts_ltz )
with rws as (
select timestamp'2023-01-01 00:00:00' ts from dual union all
select timestamp'2023-09-01 00:00:00' ts from dual union all
select timestamp'2023-01-01 00:00:00 Asia/Kolkata' ts from dual union all
select timestamp'2023-09-01 00:00:00 Asia/Kolkata' ts from dual
)
select sessiontimezone, ts, ts, ts from rws
4 row(s) inserted.
commit
Statement processed.
alter session set time_zone = 'UTC'
Statement processed.
Fetching TIMESTAMP values
select *
from t
order by id, ts_tz
ID | SESS_TZ | TS | TS_TZ | TS_LTZ | 1 | Europe/London | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +00:00 | TS 01-JAN-2023 00:00 | 2 | Europe/London | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +01:00 | TS 31-AUG-2023 23:00 | 3 | Europe/London | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 31-DEC-2022 18:30 | 4 | Europe/London | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 31-AUG-2023 18:30 | 5 | UTC | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +00:00 | TS 01-JAN-2023 00:00 | 6 | UTC | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +00:00 | TS 01-SEP-2023 00:00 | 7 | UTC | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 31-DEC-2022 18:30 | 8 | UTC | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 31-AUG-2023 18:30 | 9 | Asia/Kolkata | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 31-DEC-2022 18:30 | 10 | Asia/Kolkata | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 31-AUG-2023 18:30 | 11 | Asia/Kolkata | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 31-DEC-2022 18:30 | 12 | Asia/Kolkata | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 31-AUG-2023 18:30 |
---|
alter session set time_zone = 'Asia/Kolkata'
Statement processed.
select *
from t
order by id, ts_ltz
ID | SESS_TZ | TS | TS_TZ | TS_LTZ | 1 | Europe/London | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +00:00 | TS 01-JAN-2023 05:30 | 2 | Europe/London | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +01:00 | TS 01-SEP-2023 04:30 | 3 | Europe/London | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 01-JAN-2023 00:00 | 4 | Europe/London | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 01-SEP-2023 00:00 | 5 | UTC | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +00:00 | TS 01-JAN-2023 05:30 | 6 | UTC | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +00:00 | TS 01-SEP-2023 05:30 | 7 | UTC | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 01-JAN-2023 00:00 | 8 | UTC | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 01-SEP-2023 00:00 | 9 | Asia/Kolkata | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 01-JAN-2023 00:00 | 10 | Asia/Kolkata | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 01-SEP-2023 00:00 | 11 | Asia/Kolkata | TS 01-JAN-2023 00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TS 01-JAN-2023 00:00 | 12 | Asia/Kolkata | TS 01-SEP-2023 00:00 | TSTZ 01-SEP-2023 00:00 +05:30 | TS 01-SEP-2023 00:00 |
---|
alter session set time_zone = 'UTC'
Statement processed.
Adding time zone to timestamp
select from_tz ( timestamp'2023-01-01 00:00:00', 'Asia/Kolkata' ) ts_to_tstz,
from_tz ( cast ( sysdate as timestamp ), 'Asia/Kolkata' ) dt_to_tstz
from dual
TS_TO_TSTZ | DT_TO_TSTZ | TSTZ 01-JAN-2023 00:00 +05:30 | TSTZ 17-JAN-2023 11:29 +05:30 |
---|
FROM_TZ
select from_tz ( systimestamp, 'Asia/Kolkata' ) ts_to_tstz
from dual
ORA-00932: inconsistent datatypes: expected TIMESTAMP got TIMESTAMP WITH TIME ZONEMore Details: https://docs.oracle.com/error-help/db/ora-00932
FROM_TZ
select from_tz ( cast ( systimestamp as timestamp ), 'Asia/Kolkata' ) ts_to_tstz
from dual
TS_TO_TSTZ | TSTZ 17-JAN-2023 11:29 +05:30 |
---|
alter session set time_zone = 'UTC'
Statement processed.
Convert one time zone to another
select timestamp'2023-01-01 00:00:00 Asia/Kolkata' at time zone 'UTC' ts_to_tz,
timestamp'2023-01-01 00:00:00' at local ts_to_local,
/* Implict TS -> TSTZ with session time zone conversion! */
timestamp'2023-01-01 00:00:00' at time zone 'UTC' tz_to_tz
from dual
TS_TO_TZ | TS_TO_LOCAL | TZ_TO_TZ | TSTZ 31-DEC-2022 18:30 +00:00 | TSTZ 01-JAN-2023 00:00 +00:00 | TSTZ 01-JAN-2023 00:00 +00:00 |
---|
alter session set time_zone = 'Asia/Kolkata'
Statement processed.
select timestamp'2023-01-01 00:00:00 Asia/Kolkata' at time zone 'UTC' tz_to_tz,
timestamp'2023-01-01 00:00:00' at local ts_to_local,
/* Implict TS -> TSTZ with session time zone conversion! */
timestamp'2023-01-01 00:00:00' at time zone 'UTC' ts_to_tz
from dual
TZ_TO_TZ | TS_TO_LOCAL | TS_TO_TZ | TSTZ 31-DEC-2022 18:30 +00:00 | TSTZ 01-JAN-2023 00:00 +05:30 | TSTZ 31-DEC-2022 18:30 +00:00 |
---|
NEW_TIME for DATE time zone conversion
select new_time ( date'2023-01-01', 'PST', 'GMT' ) dt_to_dt
from dual
DT_TO_DT | DT 01-JAN-2023 08:00 |
---|
select new_time ( date'2022-01-01', 'PST', 'UTC' ) dt_to_dt
from dual
ORA-01857: not a valid time zoneMore Details: https://docs.oracle.com/error-help/db/ora-01857
Daylight saving
select timestamp'2023-03-27 00:00:00 Europe/London'
- timestamp'2023-03-26 00:00:00 Europe/London' clocks_forward,
timestamp'2023-03-27 00:00:00 +00:00'
- timestamp'2023-03-26 00:00:00 +00:00' clocks_not_forward,
timestamp'2023-10-30 00:00:00 Europe/London'
- timestamp'2023-10-29 00:00:00 Europe/London' clocks_back,
timestamp'2023-10-30 00:00:00 +00:00'
- timestamp'2023-10-29 00:00:00 +00:00' clocks_not_back
from dual
CLOCKS_FORWARD | CLOCKS_NOT_FORWARD | CLOCKS_BACK | CLOCKS_NOT_BACK | +000000000 23:00:00.000000000 | +000000001 00:00:00.000000000 | +000000001 01:00:00.000000000 | +000000001 00:00:00.000000000 |
---|