Technical Articles
Date formatter class
Intro
How many times did you need some sort of format(date, “ddMMYYYY”) thing in ABAP? I did a lot.
And how many times did you build a class/function/program to do that? I did a few.
I’m pretty sure everybody has one of these (I had, twice, in the past), but I’ve had to build it for the third time today, and I thought “why don’t you share it?”.
Mostly because I’m a cool guy, not because I need some sort of “repository”.
If anyone feels the urge to create a GIT for it, feel free to do it, I will not claim authority nor anything else, I’m happy with the amount of attention (and responsability) I currently have.
Apologies
Mainly to Paul Hardy because I builded it ignoring TDD. It’s legacy code, mate, I know it, but I’m still trying to be used to TDD when it “doesn’t feel needed” (sorta “direct code” things).
And to Matthew Billingham because I did not used the whole new ABAP syntax (same reason).
And to anyone who reads this and points me to an error code or who will feird weird reading it.
I had to use CONCATENATE because I needed to respect blanks. String operators didn’t work (or I could not make them work).
All are my faults. Sorry.
The fact the post and the code box are too narrow for any 80s and latter screens are not my fault. It’s SAP’s. Sue them. If you dare. I don’t. Really.
How-to
It’s ease, the main method of the class is the formatter one. It will process any date (no, no valid checks -yet-) and any string for format it. The method will split the string into pieces, looking for
- dd – day of the month
- tt – number of the month
- mm – short month name (three letters)
- MM – full month name
- yy – short year (last two positions)
- YY – full year
- ww – short weekday name (two letters)
- WW – full weekday name
and will keep the rest “in place”.
To be helpful (for me, hence I just added the languages I need), I added two more methods with the standard language formats (I found via google translator, so they can be wrong). Feel free to pass me more date formats, I will gladly update them.
Last thoughts
The code comes “as is”, no warrants of any kind, and I will not accept any responsability if you use it and something goes wrong. If it contains any malware, it’s not me, someone has editted it to include the evil thing on it.
Please, feel free to:
- use/copy it for free (but don’t try to get points for it, it’ll be rude)
- create the git, as I said at the beginning
- point me possible mistakes
- suggest me possible improvements
- build the tests
I will gladly (I love this word, that means “if I want”, but sounds like “happily”) apply the changes to my code and to this blog entry (if I’m still around and not formermemberized).
The code
class zcl_date_tools definition
public
abstract
create public .
public section.
class-methods:
formatdate
importing
date type dats
language type sylangu default sy-langu
format type csequence
returning value(result) type string,
w
importing
date type dats
language type sylangu default sy-langu
returning value(result) type string,
m
importing
date type dats
language type sylangu default sy-langu
returning value(result) type string,
daysofweek
importing
language type sylangu default sy-langu
returning value(result) type isu_t_days,
mediumformat
importing
language type sylangu default sy-langu
returning value(result) type string,
longformat
importing
language type sylangu default sy-langu
returning value(result) type string.
protected section.
private section.
class-methods:
allbutlasttwo
importing
text type csequence
returning value(resultado) type string,
lasttwo
importing
text type csequence
returning value(resultado) type text02.
endclass.
class zcl_date_tools implementation.
method formatdate.
data: position type i,
element type string.
if format cs 'ww' or format cs 'WW'.
data(w) = w( date = date language = language ).
endif.
if format cs 'mm' or format cs 'MM'.
data(m) = m( date = date language = language ).
endif.
do strlen( format ) times.
position = sy-index - 1.
concatenate element format+position(1) into element respecting blanks.
data(beginswith) = allbutlasttwo( element ).
data(endswith) = lasttwo( element ).
case endswith.
when 'dd'.
result = |{ result }{ beginswith }{ date+6(2) }|.
when 'nn'.
result = |{ result }{ beginswith }{ date+4(2) }|.
when 'mm'.
result = |{ result }{ beginswith }{ m(3) }|.
when 'MM'.
result = |{ result }{ beginswith }{ m+4 }|.
when 'yy'.
result = |{ result }{ beginswith }{ date+2(2) }|.
when 'YY'.
result = |{ result }{ beginswith }{ date(4) }|.
when 'ww'.
result = |{ result }{ beginswith }{ w(2) }|.
when 'WW'.
result = |{ result }{ beginswith }{ w+3 }|.
when others.
continue.
endcase.
free element.
enddo.
endmethod.
method w.
data: long type t246-langt,
short type t246-kurzt.
call function 'GET_WEEKDAY_NAME'
exporting
date = date
language = language
importing
longtext = long
shorttext = short
exceptions
calendar_id = 1
date_error = 2
not_found = 3
wrong_input = 4
others = 5.
if sy-subrc <> 0.
return.
endif.
result = |{ short }-{ long }|.
endmethod.
method m.
data: months type standard table of t247 with empty key.
call function 'MONTH_NAMES_GET'
exporting
language = language
tables
month_names = months
exceptions
month_names_not_found = 1
others = 2.
if sy-subrc <> 0.
return.
endif.
result = |{ months[ date+4(2) ]-ktx }-{ months[ date+4(2) ]-ltx }|.
endmethod.
method daysofweek.
call function 'WEEKDAY_GET'
exporting
language = language
tables
weekday = result.
endmethod.
method lasttwo.
check strlen( text ) >= 2.
data(start) = strlen( text ) - 2.
resultado = text+start.
endmethod.
method allbutlasttwo.
check strlen( text ) >= 2.
data(length) = strlen( text ) - 2.
resultado = text(length).
endmethod.
method mediumformat.
case language.
when 'S' or 'ES'. "26 de julio de 2021
result = 'dd de MM de YY'.
when 'E' or 'EN'. "July 26, 2021
result = 'MM dd, YY'.
when 'L' or 'PL'. "26 lipca 2021
result = 'dd MM YY'.
when '느' or '1P'. "26 de julho de 2021
result = 'dd de MM de YY'.
when '4' or 'RO'. "26 iulie 2021
result = 'dd de MM de YY'.
when 'F' or 'FR'. "26 juillet 2021
result = 'dd MM YY'.
endcase.
endmethod.
method longformat.
case language.
when 'S' or 'ES'. "sábado, 26 de julio de 2021
result = 'WW, dd de MM de YY'.
when 'E' or 'EN'. "Saturday, July 26, 2021
result = 'WW, MM dd, YY'.
when 'L' or 'PL'. "sobota, 26 lipca 2021
result = 'WW, dd MM YY'.
when '느' or '1P'. "Sábado, 26 de julho de 2021
result = 'WW, dd de MM de YY'.
when '4' or 'RO'. "Sâmbătă, 26 iulie 2021
result = 'WW, dd de MM de YY'.
when 'F' or 'FR'. "samedi 26 juillet 2021
result = 'WW dd MM YY'.
endcase.
endmethod.
endclass.
Aside from the formatting of the method definitions (maybe a problem with the blog editor?),
it looks fine (date formatting will never be pretty), but first thing I'd do is to change all the static methods to instance.
Reason?
I'd like to do something like
Then I can use the same format on all my date output, instead of specifying it each time in method formatdate.
I really recommend the CLEAN ABAP book. I've read it almost cover to cover, and learned new techniques and broken a few old (not good) habits.
The editor has nothing to do with it, I arrange my methods that way... too crowded, maybe, but I don't care about the contract once I've "signed it". When I need to call the methods, Eclipse saves my butt, regardless of the crappy format of the original code.
Not sure if it's right or wrong, just (atm) a matter of taste.
About the removing of the class-methodology, I guess I understood your point, but I don't recall to have any app in need of multiple data format, so I decided to keep it that way.
I think if you're going to publish code for others, the signatures need to be readable. I want to look at it and understand it before putting it into my system
But I think they need to be readable anyway. All code needs to be readable in my view. Certainly, if I came across this at 3am on a Sunday morning, and I knew where you lived... 😁
Got the point, code kindly updated.
Reward points if useful.
Tuly, points deducted. 😉
Don't you pretty print to align the parameter types? 😉
I just edited the post and added the line feeds and spaces before the new lines... you dirty mind.
But OK, just because of you and the patience you show to newbies, I'll pretty print them.
Doh!... now it looks "professional"
Almost. Keyword upper case, underscores '_' between words ... 😁
I kindly disagree, dude... no _ and all lowcase... I'd maybe consider the use of camelwhatever if the autoformatter was capable of, but underscores just "eat capacity"
If you cannot understand productionorder but you can understand production_order, there's something wrong in you... only if the word could be split in two different sentences regarding where you put the space, but I did not find the case yet.
CamelCase is to be preferred of course. But for readability when not available, _ is adequate.
You are fully entitled of course to your minority opinion
. At least they're better than prord... or lv_p1. 😮 😮
In fact, the point the Clean Code authors make is true. There will never be consensus. I don't agree with everything they say either.
yey! 🙂
humm... what about a "wrapper"?
an instance where the instanced methods will call the static ones... sounds dirty.
(o, about the book, I'm still learning from the rocket one)
You could use a wrapper of course. Still dirty.
I did used to write static methods only classes, but got bitten a few times, so now I seldom have static methods, except possible the class constructor.
I think you might well find the clean abap code book more useful - it's funny, but it's also not a bad way of learning the >= 7.40 ABAP. As I said, I learned things. 😁
(I also learned to day how to view the list when you're WRITING, in the new debugger - on SAPGui of course).
Why there is no standard class that does all this and is released to everyone? SAP keeps boasting about API Hub yet here we are, Community writing custom code for the basic functionality. Yay for Community, boo for SAP.
I'd be happy seeing SAP releasing something like that, even copying my own code without giving me points.