473,406 Members | 2,259 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Date format

I used the following query to retrieve the date in dd-mon-yyyy format.
db2 => SELECT RTRIM(CHAR(DAY(COVG_TYP_STRT_DT))) || '-' ||
RTRIM(MONTHNAME(COVG_TYP_STRT_DT)) || '-' ||
RTRIM(CHAR(YEAR(COVG_TYP_STRT_DT))) FROM twd_coverage_type

1
----------------------------------------------------------------------------------------------------------------------------
6-May-2006

1 record(s) selected.

Is there any shorter way to do this?
example:
SELECT CHAR(T1.COL_DT ,'DD-MMM-YYYY') FROM TABLE1 T1;
This works fine in oracle pl/sql but not in db2.
My db2 version is 8.2 and aix v5.3

Cheers,
San.

May 22 '06 #1
11 10529
Sandeep,

If I am not wrong, existing Timestamp_format function is not helping
you.

try something like this

CREATE FUNCTION TO_DD_MMM_YYYY (D DATE)
RETURNS VARCHAR(11)
LANGUAGE SQL
BEGIN ATOMIC
return cast (day(d) as char(2)) || '-' || cast ( MONTHNAME(D) as
char(3)) || '-' || cast ( YEAR(D) as char(4));
end@

regards,

Mehmet Baserdem

May 23 '06 #2
Mehmet Baserdem wrote:
Sandeep,

If I am not wrong, existing Timestamp_format function is not helping
you.


Indeed, you are not wrong. The TIMESTAMP_FORMAT function is comically
ridiculous. According to the documentation:

Valid format strings are:

'YYYY-MM-DD HH24:MI:SS'

When I first read this, I thought "oh, it's a typo, they must mean 'A
valid format string...'". But no, they really mean "the *only* valid
format string..."! Which had me scratching my head wondering, if you
can only specify that particular value for the second argument, why
bother having the second argument?

Anyway, here's a fun little (!) function which is a bit more flexible.
It's probably horribly inefficient compared to a proper C
implementation, but at least it allows you to specify more than one
format :-)

The function is based off the strftime() function and accepts the
following substitution templates in the AFORMAT parameter:

Template Meaning
======== ==================================================
%A Locale's full weekday name.
%B Locale's full month name.
%c Locale's appropriate date and time representation.
%d Day of the month as a decimal number [01,31].
%H Hour (24-hour clock) as a decimal number [00,23].
%I Hour (12-hour clock) as a decimal number [01,12].
%j Day of the year as a decimal number [001,366].
%m Month as a decimal number [01,12].
%M Minute as a decimal number [00,59].
%p Locale's equivalent of either AM or PM.
%S Second as a decimal number [00,61].
%U Week number of the year (Sunday as the first day of the
week) as a decimal number [01,54].
%w Weekday as a decimal number [1(Sunday),7].
%W Week number of the year (Monday as the first day of the
week) as a decimal number [01,53].
%x Locale's appropriate date representation.
%X Locale's appropriate time representation.
%y Year without century as a decimal number [00,99].
%Y Year with century as a decimal number.
%Z Time zone offset (no characters if no time zone exists).
%% A literal "%" character.

Note this isn't exactly the same as the "normal" strftime() function as
things like abbreviated day / month name are missing. That said, it's
not difficult to expand the function if you want to add these things.

Also note that, unlike the TIMESTAMP_FORMAT function the format
parameter is specified first (I did it this way round because that's
the order of the parameters in the original strftime() function, but of
course you can switch them back 'round if you want).

Overloaded versions that accept DATE and TIME parameters are also
provided, as is a version which takes only the format as a parameter
and uses the CURRENT TIMESTAMP special register for the timestamp to be
formatted:

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100), ATIMESTAMP TIMESTAMP)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME1
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
BEGIN ATOMIC
DECLARE I SMALLINT;
DECLARE C CHAR(1);
DECLARE RESULT VARCHAR(100);
SET I = 1;
SET RESULT = '';
WHILE I <= LENGTH(AFORMAT) DO
SET C = SUBSTR(AFORMAT, I, 1);
IF C = '%' AND I < LENGTH(AFORMAT) THEN
SET RESULT = RESULT ||
CASE SUBSTR(AFORMAT, I + 1, 1)
WHEN '%' THEN '%'
WHEN 'A' THEN DAYNAME(ATIMESTAMP)
WHEN 'B' THEN MONTHNAME(ATIMESTAMP)
WHEN 'c' THEN
CHAR(DATE(ATIMESTAMP), LOCAL) || ' ' ||
CHAR(TIME(ATIMESTAMP), LOCAL)
WHEN 'd' THEN SUBSTR(DIGITS(DAY(ATIMESTAMP)), 9)
WHEN 'H' THEN SUBSTR(DIGITS(HOUR(ATIMESTAMP)), 9)
WHEN 'I' THEN
SUBSTR(DIGITS(CASE
WHEN HOUR(ATIMESTAMP) = 0 THEN 12
WHEN HOUR(ATIMESTAMP) > 12 THEN HOUR(ATIMESTAMP) - 12
ELSE HOUR(ATIMESTAMP)
END), 9)
WHEN 'j' THEN SUBSTR(DIGITS(DAYOFYEAR(ATIMESTAMP)), 8)
WHEN 'm' THEN SUBSTR(DIGITS(MONTH(ATIMESTAMP)), 9)
WHEN 'M' THEN SUBSTR(DIGITS(MINUTE(ATIMESTAMP)), 9)
WHEN 'P' THEN CASE WHEN HOUR(ATIMESTAMP) < 12 THEN 'AM' ELSE
'PM' END
WHEN 'S' THEN SUBSTR(DIGITS(SECOND(ATIMESTAMP)), 9)
WHEN 'U' THEN SUBSTR(DIGITS(WEEK(ATIMESTAMP)), 9)
WHEN 'w' THEN CHAR(DAYOFWEEK(ATIMESTAMP))
WHEN 'W' THEN SUBSTR(DIGITS(WEEK_ISO(ATIMESTAMP)), 9)
WHEN 'x' THEN CHAR(DATE(ATIMESTAMP), LOCAL)
WHEN 'X' THEN CHAR(TIME(ATIMESTAMP), LOCAL)
WHEN 'y' THEN SUBSTR(DIGITS(YEAR(ATIMESTAMP)), 9)
WHEN 'Y' THEN SUBSTR(DIGITS(YEAR(ATIMESTAMP)), 7)
WHEN 'Z' THEN
CASE WHEN CURRENT TIMEZONE < 0 THEN '-' ELSE '+' END ||
SUBSTR(DIGITS(CURRENT TIMEZONE), 1, 2) || ':' ||
SUBSTR(DIGITS(CURRENT TIMEZONE), 3, 2)
ELSE ''
END;
SET I = I + 2;
ELSE
SET RESULT = RESULT || C;
SET I = I + 1;
END IF;
END WHILE;
RETURN RESULT;
END@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100), ADATE DATE)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME2
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
STRFTIME(AFORMAT, TIMESTAMP(ADATE, '00:00:00'))@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100), ATIME TIME)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME3
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
STRFTIME(AFORMAT, TIMESTAMP('0001-01-01', ATIME))@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100))
RETURNS VARCHAR(100)
SPECIFIC STRFTIME4
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
STRFTIME(AFORMAT, CURRENT TIMESTAMP)@

Some examples of usage:

STRFTIME('%A, %d %B %Y') = 'Tuesday, 23 May 2006'
STRFTIME('%Y-%m-%dT%H:%M:%S%Z') = '2006-05-23T23:47:10+01:00'
STRFTIME('Day: %d') = 'Day: 23'
STRFTIME('%Y-%j (DOY)') = '2006-143 (DOY)'
STRFTIME('%I:%M:%S %P') = '11:58:57 PM'
If you find any bugs or need a hand extending it to handle other
things, let me know.

HTH,

Dave.

--

May 23 '06 #3
You wrote "%p Locale's equivalent of either AM or PM." in
"Template Meaning".
But you coded it as %P and in "Some examples of usage:" you showed
STRFTIME('%I:%M:%S %P') = '11:58:57 PM'
Which is right?

May 24 '06 #4
Here is another trial for the function. I used %p for AM or PM.

CREATE FUNCTION STRFTIME_N(AFORMAT VARCHAR(100), ATIMESTAMP TIMESTAMP)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME_N
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(AFORMAT
, '%A', DAYNAME(ATIMESTAMP))
, '%B', MONTHNAME(ATIMESTAMP))
, '%c', CHAR(DATE(ATIMESTAMP), LOCAL) ||' '||
CHAR(TIME(ATIMESTAMP), LOCAL))
, '%d', SUBSTR(DIGITS(DAY(ATIMESTAMP)),9,2))
, '%H', SUBSTR(DIGITS(HOUR(ATIMESTAMP)),9,2))
, '%I', SUBSTR(DIGITS(MOD(HOUR(ATIMESTAMP)+11,12)+1),9,2))
, '%j', SUBSTR(DIGITS(DAYOFYEAR(ATIMESTAMP)),8,3))
, '%m', SUBSTR(DIGITS(MONTH(ATIMESTAMP)),9,2))
, '%M', SUBSTR(DIGITS(MINUTE(ATIMESTAMP)),9,2))
, '%p', SUBSTR('AMPM',1+HOUR(ATIMESTAMP)/12*2,2))
, '%S', SUBSTR(DIGITS(SECOND(ATIMESTAMP)),9,2))
, '%U', SUBSTR(DIGITS(WEEK(ATIMESTAMP)),9,2))
, '%w', SUBSTR(CHAR(DAYOFWEEK(ATIMESTAMP)),1,1))
, '%W', SUBSTR(DIGITS(WEEK_ISO(ATIMESTAMP)),9,2))
, '%x', CHAR(DATE(ATIMESTAMP),LOCAL))
, '%X', CHAR(TIME(ATIMESTAMP),LOCAL))
, '%y', SUBSTR(DIGITS(YEAR(ATIMESTAMP)),9,2))
, '%Y', SUBSTR(DIGITS(YEAR(ATIMESTAMP)),7,4))
, '%Z', SUBSTR('-++',2+INT(SIGN(CURRENT_TIMEZONE)),1)
||
TRANSLATE('AB:CD',DIGITS(CURRENT_TIMEZONE),'ABCDEF '))
, '%%', '%');

May 24 '06 #5
Tonkuma wrote:
You wrote "%p Locale's equivalent of either AM or PM." in
"Template Meaning".
But you coded it as %P and in "Some examples of usage:" you showed
STRFTIME('%I:%M:%S %P') = '11:58:57 PM'
Which is right?


D'oh! You're absolutely right. Going by the strftime man-page on my
Linux box, it ought to be lower-case 'p'. There's a few other changes
I've made and some tidying up (e.g. I replaced most of the SUBSTR()
calls with RIGHT() which is a bit clearer under the circumstances.

I've added the abbreviated versions of weekday and month name simply by
taking the first 3 characters of the output of DAYNAME and MONTHNAME.
Probably incorrect for anything but an English locale, but coming up
with anything more complex ... well ... I'm lazy :-)

I've also added some "non-standard" substitutions like '%q' for the
quarter number, and '%h' for half, so you can have templates like:

STRFTIME('%qQ%y') = '2Q06'

(which are some representations of approximate dates I've seen
occassionaly a fairly common representation of approximate dates in
business).

Here's the revised version:

DROP SPECIFIC FUNCTION STRFTIME4@
DROP SPECIFIC FUNCTION STRFTIME3@
DROP SPECIFIC FUNCTION STRFTIME2@
DROP SPECIFIC FUNCTION STRFTIME1@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100), ATIMESTAMP TIMESTAMP)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME1
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
BEGIN ATOMIC
DECLARE I SMALLINT;
DECLARE C CHAR(1);
DECLARE RESULT VARCHAR(100);
SET I = 1;
SET RESULT = '';
WHILE I <= LENGTH(AFORMAT) DO
SET C = SUBSTR(AFORMAT, I, 1);
IF C = '%' AND I < LENGTH(AFORMAT) THEN
SET RESULT = RESULT ||
CASE SUBSTR(AFORMAT, I + 1, 1)
WHEN '%' THEN '%'
WHEN 'a' THEN LEFT(DAYNAME(ATIMESTAMP), 3)
WHEN 'A' THEN DAYNAME(ATIMESTAMP)
WHEN 'b' THEN LEFT(MONTHNAME(ATIMESTAMP), 3)
WHEN 'B' THEN MONTHNAME(ATIMESTAMP)
WHEN 'c' THEN
CHAR(DATE(ATIMESTAMP), LOCAL) || ' ' ||
CHAR(TIME(ATIMESTAMP), LOCAL)
WHEN 'd' THEN RIGHT(DIGITS(DAY(ATIMESTAMP)), 2)
WHEN 'h' THEN CASE WHEN MONTH(ATIMESTAMP) < 6 THEN '1' ELSE
'2' END
WHEN 'H' THEN RIGHT(DIGITS(HOUR(ATIMESTAMP)), 2)
WHEN 'I' THEN
RIGHT(DIGITS(CASE
WHEN HOUR(ATIMESTAMP) = 0 THEN 12
WHEN HOUR(ATIMESTAMP) > 12 THEN HOUR(ATIMESTAMP) - 12
ELSE HOUR(ATIMESTAMP)
END), 2)
WHEN 'j' THEN RIGHT(DIGITS(DAYOFYEAR(ATIMESTAMP)), 3)
WHEN 'm' THEN RIGHT(DIGITS(MONTH(ATIMESTAMP)), 2)
WHEN 'M' THEN RIGHT(DIGITS(MINUTE(ATIMESTAMP)), 2)
WHEN 'p' THEN CASE WHEN HOUR(ATIMESTAMP) < 12 THEN 'AM' ELSE
'PM' END
WHEN 'q' THEN LEFT(CHAR(QUARTER(ATIMESTAMP)), 1)
WHEN 'S' THEN RIGHT(DIGITS(SECOND(ATIMESTAMP)), 2)
WHEN 'U' THEN RIGHT(DIGITS(WEEK(ATIMESTAMP)), 2)
WHEN 'w' THEN LEFT(CHAR(DAYOFWEEK(ATIMESTAMP)), 1)
WHEN 'W' THEN RIGHT(DIGITS(WEEK_ISO(ATIMESTAMP)), 2)
WHEN 'x' THEN CHAR(DATE(ATIMESTAMP), LOCAL)
WHEN 'X' THEN CHAR(TIME(ATIMESTAMP), LOCAL)
WHEN 'y' THEN RIGHT(DIGITS(YEAR(ATIMESTAMP)), 2)
WHEN 'Y' THEN RIGHT(DIGITS(YEAR(ATIMESTAMP)), 4)
WHEN 'Z' THEN
CASE WHEN CURRENT TIMEZONE < 0 THEN '-' ELSE '+' END ||
SUBSTR(DIGITS(CURRENT TIMEZONE), 1, 2) || ':' ||
SUBSTR(DIGITS(CURRENT TIMEZONE), 3, 2)
ELSE ''
END;
SET I = I + 2;
ELSE
SET RESULT = RESULT || C;
SET I = I + 1;
END IF;
END WHILE;
RETURN RESULT;
END@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100), ADATE DATE)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME2
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
STRFTIME(AFORMAT, TIMESTAMP(ADATE, '00:00:00'))@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100), ATIME TIME)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME3
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
STRFTIME(AFORMAT, TIMESTAMP('0001-01-01', ATIME))@

CREATE FUNCTION STRFTIME(AFORMAT VARCHAR(100))
RETURNS VARCHAR(100)
SPECIFIC STRFTIME4
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
STRFTIME(AFORMAT, CURRENT TIMESTAMP)@
And some more examples:

STRFTIME('%d-%a-%Y') = '24-Wed-2006'
STRFTIME('%qQ%y') = '2Q06'
STRFTIME('%hH%y') = '1H06'
STRFTIME('%YQ%q') = '2006Q2'

HTH,

Dave.

--

May 24 '06 #6
Tonkuma wrote:
Here is another trial for the function. I used %p for AM or PM.

CREATE FUNCTION STRFTIME_N(AFORMAT VARCHAR(100), ATIMESTAMP TIMESTAMP)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME_N
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
REPLACE(
REPLACE( [...snipped lots of REPLACE calls...]
)),7,4)) , '%Z', SUBSTR('-++',2+INT(SIGN(CURRENT_TIMEZONE)),1)
||
TRANSLATE('AB:CD',DIGITS(CURRENT_TIMEZONE),'ABCDEF '))
, '%%', '%');


Ah, I had originally thought about using nested REPLACE calls, but
there's a problem with that approach. Depending on the order of
replacements escaped % symbols in the template (i.e. %%) can cause
problems. Consider the format:

'%%p'

Which ought to result in the string '%p'. In your version of the
function, %p get's substitution before %% so initially you wind up with
'%PM' or possibly '%AM'. Thankfully, the replacement for %A has already
been done by that point, but if the ordering had been different you
might have wound up with 'WednesdayM'.

Now, if the substitution for %% is done first, you initially wind up
with '%p' but then the substitution for %p comes along and transforms
that into AM or PM.

Basically, this function can't be *reliably* written using nested (or
serial) REPLACE calls. It's just the wrong algorithm for it, sorry.
Dave.

--

May 24 '06 #7
> Consider the format:

'%%p'
Which ought to result in the string '%p'. In your version of the
function, %p get's substitution before %% so initially you wind up with
'%PM' or possibly '%AM'.


How about first change '%%' to a character which usually is not used(I
tried CHR(1)).
And, I changed REPLACE sequence.
Put first characters which there are possibility to be produced by %A',
DAYNAME(ATIMESTAMP) and '%B', MONTHNAME(ATIMESTAMP) before them.(In
English)

DROP FUNCTION STRFTIME_N;

CREATE FUNCTION STRFTIME_N(AFORMAT VARCHAR(100), ATIMESTAMP TIMESTAMP)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME_N
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(AFORMAT, '%%', CHR(1))
, '%M', SUBSTR(DIGITS(MINUTE(ATIMESTAMP)),9,2))
, '%W', SUBSTR(DIGITS(WEEK_ISO(ATIMESTAMP)),9,2))
, '%S', SUBSTR(DIGITS(SECOND(ATIMESTAMP)),9,2))
, '%A', DAYNAME(ATIMESTAMP))
, '%B', MONTHNAME(ATIMESTAMP))
, '%c', CHAR(DATE(ATIMESTAMP),LOCAL) ||' '||
CHAR(TIME(ATIMESTAMP),LOCAL))
, '%d', SUBSTR(DIGITS(DAY(ATIMESTAMP)),9,2))
, '%h', SUBSTR(CHAR(QUARTER(ATIMESTAMP)/2),1,1))
, '%H', SUBSTR(DIGITS(HOUR(ATIMESTAMP)),9,2))
, '%I', SUBSTR(DIGITS(MOD(HOUR(ATIMESTAMP)+11,12)+1),9,2))
, '%j', SUBSTR(DIGITS(DAYOFYEAR(ATIMESTAMP)),8,3))
, '%m', SUBSTR(DIGITS(MONTH(ATIMESTAMP)),9,2))
, '%p', SUBSTR('AMPM',1+HOUR(ATIMESTAMP)/12*2,2))
, '%q', SUBSTR(CHAR(QUARTER(ATIMESTAMP)),1,1))
, '%U', SUBSTR(DIGITS(WEEK(ATIMESTAMP)),9,2))
, '%w', SUBSTR(CHAR(DAYOFWEEK(ATIMESTAMP)),1,1))
, '%x', CHAR(DATE(ATIMESTAMP),LOCAL))
, '%X', CHAR(TIME(ATIMESTAMP),LOCAL))
, '%y', SUBSTR(DIGITS(YEAR(ATIMESTAMP)),9,2))
, '%Y', SUBSTR(DIGITS(YEAR(ATIMESTAMP)),7,4))
, '%Z', SUBSTR('-++',2+INT(SIGN(CURRENT_TIMEZONE)),1)
||
TRANSLATE('AB:CD',DIGITS(CURRENT_TIMEZONE),'ABCDEF '))
, CHR(1), '%');

Some result examples:
'%I:%M:%S %p' => 11:48:08 AM
'%I:%M:%S %%p' => 11:48:17 %p
'%I:%M:%S %%%p' => 11:48:24 %AM
'%I:%M:%S %%%%p' => 11:48:35 %%p
'%I:%M:%S %%%%%p' => 11:48:49 %%AM
'%qQ%y' => 2Q06

May 25 '06 #8
Tonkuma wrote:
Consider the format:

'%%p'
Which ought to result in the string '%p'. In your version of the
function, %p get's substitution before %% so initially you wind up
with '%PM' or possibly '%AM'.
How about first change '%%' to a character which usually is not used(I
tried CHR(1)).
And, I changed REPLACE sequence.
Put first characters which there are possibility to be produced by
%A', DAYNAME(ATIMESTAMP) and '%B', MONTHNAME(ATIMESTAMP) before
them.(In English)


Yes, that'll work ... for now :-) Although this version of the function
is now correct, what happens if someone wishes to extend the behavior
of the function? Although it is possible to do so safely, it requires
careful consideration of the order of replacement. In other words, this
definition is less maintainable than the iterative version.

There's also the question of performance. I'm unsure if this version
performs better or worse than the iterative version:

The iterative version makes a single pass of the template string,
constructing the output by repeatedly concatenating (urgh). This pass
is done in SQL and therefore (I assume) is going to be considerably
slower than a single pass done by the REPLACE() function (in compiled
code).

This definition of the function makes 23 passes of the template string
(in compiled code, by calling REPLACE 23 times). Is this quicker or
slower than a single pass done in SQL (especially when taking all that
concatenation into account)? I'm not sure.

If one wants to get pedantic about performance, another thing to
consider would be when or if the replacement strings are calculated. I
suspect that all the replacement strings are calculated once and once
only in this version (at runtime the REPLACE function doesn't know in
advance whether a template occurs in the format string, hence each call
to REPLACE *must* occur, requiring that the parameters for each call
are evaluated).

In contrast I suspect the iterative version calculates replacement
strings as and when required (although I'm not sure about this - it
rather depends on how the big CASE statement in the code is
interpreted).

Therefore this version would probably have a performance advantage when
a substitution template occurs multiple times in the format string (the
substituted value would only be calculated once), while the iterative
version would perform better if a small number of templates occurred
once within the format string.

In conclusion, I suspect typical use-cases of this function fit the
optimal case of the iterative version better than this version, but one
would have to profile both functions to find out which actually
performs better in practice.

For me, the maintainability is more important than the performance, so
I'll be sticking with the iterative version for now. That said, I like
some of the modifications you've made:
DROP FUNCTION STRFTIME_N;

CREATE FUNCTION STRFTIME_N(AFORMAT VARCHAR(100), ATIMESTAMP TIMESTAMP)
RETURNS VARCHAR(100)
SPECIFIC STRFTIME_N
LANGUAGE SQL
DETERMINISTIC
NO EXTERNAL ACTION
CONTAINS SQL
RETURN
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(AFORMAT, '%%', CHR(1))
, '%M', SUBSTR(DIGITS(MINUTE(ATIMESTAMP)),9,2))
, '%W', SUBSTR(DIGITS(WEEK_ISO(ATIMESTAMP)),9,2))
, '%S', SUBSTR(DIGITS(SECOND(ATIMESTAMP)),9,2))
, '%A', DAYNAME(ATIMESTAMP))
, '%B', MONTHNAME(ATIMESTAMP))
, '%c', CHAR(DATE(ATIMESTAMP),LOCAL) ||' '||
CHAR(TIME(ATIMESTAMP),LOCAL))
, '%d', SUBSTR(DIGITS(DAY(ATIMESTAMP)),9,2))
, '%h', SUBSTR(CHAR(QUARTER(ATIMESTAMP)/2),1,1))
, '%H', SUBSTR(DIGITS(HOUR(ATIMESTAMP)),9,2))
, '%I', SUBSTR(DIGITS(MOD(HOUR(ATIMESTAMP)+11,12)+1),9,2))
, '%j', SUBSTR(DIGITS(DAYOFYEAR(ATIMESTAMP)),8,3))
, '%m', SUBSTR(DIGITS(MONTH(ATIMESTAMP)),9,2))
, '%p', SUBSTR('AMPM',1+HOUR(ATIMESTAMP)/12*2,2))
That's a lot nicer than my messy CASE expression for the AM/PM case
there.
, '%q', SUBSTR(CHAR(QUARTER(ATIMESTAMP)),1,1))
, '%U', SUBSTR(DIGITS(WEEK(ATIMESTAMP)),9,2))
, '%w', SUBSTR(CHAR(DAYOFWEEK(ATIMESTAMP)),1,1))
, '%x', CHAR(DATE(ATIMESTAMP),LOCAL))
, '%X', CHAR(TIME(ATIMESTAMP),LOCAL))
, '%y', SUBSTR(DIGITS(YEAR(ATIMESTAMP)),9,2))
, '%Y', SUBSTR(DIGITS(YEAR(ATIMESTAMP)),7,4))
, '%Z', SUBSTR('-++',2+INT(SIGN(CURRENT_TIMEZONE)),1)
||
TRANSLATE('AB:CD',DIGITS(CURRENT_TIMEZONE),'ABCDEF '))
, CHR(1), '%');
Argh! I keep forgetting TRANSLATE can be used for things like this -
much better than my horrible code on the TIMEZONE replacement, and
that's an interesting way of getting the sign prefixed as well.
Some result examples:
'%I:%M:%S %p' => 11:48:08 AM
'%I:%M:%S %%p' => 11:48:17 %p
'%I:%M:%S %%%p' => 11:48:24 %AM
'%I:%M:%S %%%%p' => 11:48:35 %%p
'%I:%M:%S %%%%%p' => 11:48:49 %%AM
'%qQ%y' => 2Q06


Thanks,

Dave.

--

May 25 '06 #9
hey Sandeep,

I needed a query with dates separated by '/ '. I took the sample from
your SQL..

SELECT RTRIM(CHAR(DAY(lst_updt_tms))) || '/' ||
RTRIM(MONTHNAME(lst_updt_tms)) || '/' ||
RTRIM(CHAR(YEAR(lst_updt_tms))) FROM db2nci.t_rpt_typ

Thanks a lot...
RaInDeEr

May 25 '06 #10
Glad that it helped you!!

Cheers,
Sandeep.

May 25 '06 #11
You are right. I agree with you.
My main intention was to show the rich functional capabilities of
non-procedural part of SQL Language, including expresssions and DB2
supplied functions.

Anyway, I found a error in my code.
, '%h', SUBSTR(CHAR(QUARTER(ATIMESTAMP)/2),1,1))

is wrong. it should be the following
, '%h', SUBSTR(CHAR((QUARTER(ATIMESTAMP)+1)/2),1,1))

May 26 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Alistair | last post by:
it's the idiot with his query strings again...."yippeee" I hear aaron shout this time the problem is with a date format query I have a query string thus strSQL = "SELECT * FROM users where...
2
by: Ian | last post by:
I have a problem I hope someone can point out where I am going wrong. I need to store a date/time in a cookie ( ie the date a visitor last visited ) However the date format changes to US, despite...
1
by: jt | last post by:
I posted this yesterday, but I am not seeing this out yet: I am having problems with updating a date field in a certain format. The data is stored in an Oracle database. The date is...
15
by: Simon Brooke | last post by:
I'm investigating a bug a customer has reported in our database abstraction layer, and it's making me very unhappy. Brief summary: I have a database abstraction layer which is intended to...
6
by: Dario Di Bella | last post by:
Hi all, we have the following urgent issue affecting our development team. Initially we had one particular workstation that failed executing queries on a DB2 database, raising an invalid date...
5
by: Macca | last post by:
Hi, I have a table which has a date/time field. I am storing them as follows :- 01/01/2005 11:25 01/01/2005 19:44 02/01/2005 05:04
20
by: andreas | last post by:
When I copy a vb.net project using date formats from one PC with a windows date format f.e. dd/mm/yyyy to another PC having a format yy/mm/dd then I get errors. How can I change for a while in the...
2
by: thewilldog | last post by:
Hello, I've reviewed the archives here to address the issue, but I'm still running into problems. I've got a table field populated with the record date in text "YYYYMMDD" To convert it into a...
10
by: ARC | last post by:
Hello all, General question for back-end database that has numerous date fields where the database will be used in regions that put the month first, and regions that do not. Should I save a...
3
by: Tony WONG | last post by:
The date format (control panel) of testing (VS2005) and production platform are yyyy/mm/dd. i run preview from testing (VS2005). The date format is yyyy/mm/dd however, when i put the code to...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.