Reputation: 787
I'm having issues with proper month abbreviation values based on what I can find online (for example) whereas I've tried using both "English" and "American" in my NLS_DATE_LANGUAGE parameter, but the underlying values aren't displaying what I'd like to based on the common standard found through various other sites.
As mentioned, I've tried both:
SELECT TO_CHAR(pDate, 'Mon dd, yyyy', 'NLS_DATE_LANGUAGE = American') FROM DUAL;
SELECT TO_CHAR(pDate, 'Mon dd, yyyy', 'NLS_DATE_LANGUAGE = English') FROM DUAL;
My months are coming out as followed, so most months should have the trailing "." value except for May, June, and July, and "Jun", should be "June":
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
I can easily add a format exception based on the month (e.g. "Mon." instead of "Mon", except for months 5-6-7), but just figured I'd ask the question if someone knows of any other language or territory values that could resolve this instead of creating some exception logic by month. I also produce the output with "French" and the output works perfectly with the abbreviations including the "." despite just passing "Mon dd, YYYY"
Upvotes: 1
Views: 12377
Reputation: 23578
Here's one way of doing it - note that you didn't mention September, which is commonly abbreviated to Sept.
:
with months as (select add_months(trunc(sysdate, 'yyyy'), level -1) mon
from dual
connect by level <= 12)
select mon,
case when to_char(mon, 'mm') in ('05', '06', '07') then to_char(mon, 'fmMonth fmdd, yyyy', 'NLS_DATE_LANGUAGE = English')
when to_char(mon, 'mm') = '09' then substr(to_char(mon, 'fmMonth', 'NLS_DATE_LANGUAGE = English'), 1, 4)||to_char(mon, '. dd, yyyy', 'NLS_DATE_LANGUAGE = English')
else to_char(mon, 'Mon. dd, yyyy', 'NLS_DATE_LANGUAGE = English')
end abbrev_mon
from months;
MON ABBREV_MON
--------- ------------------------------------
01-JAN-16 Jan. 01, 2016
01-FEB-16 Feb. 01, 2016
01-MAR-16 Mar. 01, 2016
01-APR-16 Apr. 01, 2016
01-MAY-16 May 01, 2016
01-JUN-16 June 01, 2016
01-JUL-16 July 01, 2016
01-AUG-16 Aug. 01, 2016
01-SEP-16 Sept. 01, 2016
01-OCT-16 Oct. 01, 2016
01-NOV-16 Nov. 01, 2016
01-DEC-16 Dec. 01, 2016
Upvotes: 2
Reputation: 191275
There is no Oracle NLS_DATE_LANGUAGE value that produces the output you expect (I just checked them all!). You need special handling for certain values, which is mostly based on length, but the example you linked to and other style guides (e.g. AP and Princeton, and this) suggest you should have 'Sept.' for September, rather than Sep.
.
The simplest thing is to hard-code them:
select case extract(month from add_months(trunc(sysdate, 'YYYY'), level - 1))
when 1 then 'Jan.' when 2 then 'Feb.' when 3 then 'Mar.' when 4 then 'Apr.'
when 5 then 'May' when 6 then 'June' when 7 then 'July' when 8 then 'Aug.'
when 9 then 'Sept.' when 10 then 'Oct.' when 11 then 'Nov.' else 'Dec.' end
from dual
connect by level <= 12;
CASEE
-----
Jan.
Feb.
Mar.
Apr.
May
June
July
Aug.
Sept.
Oct.
Nov.
Dec.
You can use a function to use your custom conversion:
create or replace function my_to_char(p_date date, p_fmt varchar2) return varchar2 is
l_str varchar2(30);
l_month varchar2(5);
begin
l_month := case extract(month from p_date)
when 1 then 'Jan.' when 2 then 'Feb.' when 3 then 'Mar.' when 4 then 'Apr.'
when 5 then 'May' when 6 then 'June' when 7 then 'July' when 8 then 'Aug.'
when 9 then 'Sept.' when 10 then 'Oct.' when 11 then 'Nov.' else 'Dec.' end;
return to_char(p_date, replace(p_fmt, 'Mon', '"' || l_month || '"'));
end;
/
select my_to_char(date '2016-04-15' , 'DD Mon YYYY') as result from dual;
RESULT
--------------------
15 Apr. 2016
I've kept the function simple (ish); you need to be more clever about replacing 'Mon', (a) so you don't catch 'Month', and (b) to allow for different case ('mon', 'Mon', 'MON'). You may not actually need that amount of flexibility though, and if you do you can extend this kind of approach.
Upvotes: 4
Reputation: 167972
Oracle Setup
CREATE FUNCTION to_char_abbr_month(
in_date DATE,
in_nls VARCHAR2
) RETURN VARCHAR2 DETERMINISTIC
IS
BEGIN
RETURN REGEXP_REPLACE(
TRIM( TO_CHAR( in_date, 'Month', in_nls ) ),
'(\w{3})\w{2,}',
'\1.'
)
|| ' ' || TO_CHAR( in_date, 'dd, yyyy', in_nls );
END;
/
Query:
SELECT to_char_abbr_month(
DATE '2016-01-01',
'NLS_DATE_LANGUAGE = American'
)
FROM DUAL
Output
Jan. 01, 2016
Upvotes: 1