Determining the active formatting settings in ABAP - abap

As the ABAP documentation of Formatting Settings explains:
The formatting settings are set as follows:
At the start of an internal session they are determined by the related default settings in the fixed values in the user master record of the current user.
Using the statement SET COUNTRY, this default setting for the current internal session can be overwritten using country-specific formats.
But as the ABAP documentation of SET COUNTRY makes clear, there is no way to query what's actually been set with this statement:
Do not confuse the statement SET COUNTRY with the obsolete addition COUNTRY of the statement SET LOCALE LANGUAGE, used for setting the text environment. In particular, it does not have a corresponding GET COUNTRY statement.
Indeed, the ABAP documentation of GET LOCALE - obsolete parameters mentions:
The addition COUNTRY was intended for reading the country key of the current text environment explicitly. cntry expects a character-like data object. The function of this addition was not implemented in full and the result is undefined.
The addition COUNTRY of the statement GET LOCALE does not extract the formatting setting that can be set using SET COUNTRY.
Which leaves me with a bit of a conundrum. I could determine my user defaults with FM SUSR_GET_USER_DEFAULTS. I could figure out the setting for the country from table T005X. But I have no way of figuring out which specific country format was set, or even if one was set in the active session!
How do I determine which formatting settings are currently active?
Bonus question: is there a way to figure this out in the Debugger?

Maybe you can use the function module CLSE_SELECT_USR01.
The following example:
REPORT test.
START-OF-SELECTION.
DATA: decimal_sign , separator.
PERFORM output.
SET COUNTRY 'US'.
PERFORM output.
FORM output.
CALL FUNCTION 'CLSE_SELECT_USR01'
* EXPORTING
* USERNAME = sy-uname
* IV_DELETE_BUFFER = ' '
IMPORTING
* X_USR01 =
* DATE_FORMAT =
decimal_sign = decimal_sign
separator = separator.
WRITE: / 'DECIMAL_SIGN', decimal_sign, 'separator', separator.
ENDFORM.
shows:
My default locale is DE, so I get the actual setting for decimals.
From your comment:
Unfortunately I have to parse and analyse output data that's prepared for screen display from potentially dozens of different form sources.
Do you get the output at runtime or a previous run? Because there is no time machine to get the locale from a call in the past :)

The ABAP statement SET COUNTRY may change the date format, the time format (since ABAP 7.02) and the number format, but there's officially no reverse way to get the current active country code (as you quoted in your question, based on the ABAP documentation). It's quite logical because, for instance, the current number format may be different from the current country code, so it's better to test the directly the kind of format you need to use, as follows.
To detect the current date format, use the official way which returns a character, whose possible values are described in the ABAP documentation of Date Formats):
DATA(current_date_format) = CL_ABAP_DATFM=>GET_DATFM( ).
To detect the current time format, use the official way which returns a character:
DATA(current_time_format) = CL_ABAP_TIMEFM=>GET_ENVIRONMENT_TIMEFM( ).
It returns one of the following values, with an example value corresponding to noon + 5 minutes and 10 seconds (the example value is given if it's output on at least 11 characters):
0 : 12:05:10 (0 to 23)
1 : 12:05:10 PM (0 to 12)
2 : 12:05:10 pm (0 to 12)
3 : 00:05:10 PM (0 to 11)
4 : 00:05:10 pm (0 to 11)
To detect the current number format, based on the idea from #Gert Beukema, you may do as follows:
DATA(current_number_format) = SWITCH usr01-dcpfm(
|{ 1000 NUMBER = ENVIRONMENT DECIMALS = 1 }|
WHEN '1.000,00' THEN ' '
WHEN '1,000.00' THEN 'X'
WHEN '1 000,00' THEN 'Y' ).
NB: the values , X and Y which are returned by this expression are the same values as those used in tables-columns USR01-DCPFM and T005X-XDEZP.

Related

How to get the current language environment (SET COUNTRY)? [duplicate]

As the ABAP documentation of Formatting Settings explains:
The formatting settings are set as follows:
At the start of an internal session they are determined by the related default settings in the fixed values in the user master record of the current user.
Using the statement SET COUNTRY, this default setting for the current internal session can be overwritten using country-specific formats.
But as the ABAP documentation of SET COUNTRY makes clear, there is no way to query what's actually been set with this statement:
Do not confuse the statement SET COUNTRY with the obsolete addition COUNTRY of the statement SET LOCALE LANGUAGE, used for setting the text environment. In particular, it does not have a corresponding GET COUNTRY statement.
Indeed, the ABAP documentation of GET LOCALE - obsolete parameters mentions:
The addition COUNTRY was intended for reading the country key of the current text environment explicitly. cntry expects a character-like data object. The function of this addition was not implemented in full and the result is undefined.
The addition COUNTRY of the statement GET LOCALE does not extract the formatting setting that can be set using SET COUNTRY.
Which leaves me with a bit of a conundrum. I could determine my user defaults with FM SUSR_GET_USER_DEFAULTS. I could figure out the setting for the country from table T005X. But I have no way of figuring out which specific country format was set, or even if one was set in the active session!
How do I determine which formatting settings are currently active?
Bonus question: is there a way to figure this out in the Debugger?
Maybe you can use the function module CLSE_SELECT_USR01.
The following example:
REPORT test.
START-OF-SELECTION.
DATA: decimal_sign , separator.
PERFORM output.
SET COUNTRY 'US'.
PERFORM output.
FORM output.
CALL FUNCTION 'CLSE_SELECT_USR01'
* EXPORTING
* USERNAME = sy-uname
* IV_DELETE_BUFFER = ' '
IMPORTING
* X_USR01 =
* DATE_FORMAT =
decimal_sign = decimal_sign
separator = separator.
WRITE: / 'DECIMAL_SIGN', decimal_sign, 'separator', separator.
ENDFORM.
shows:
My default locale is DE, so I get the actual setting for decimals.
From your comment:
Unfortunately I have to parse and analyse output data that's prepared for screen display from potentially dozens of different form sources.
Do you get the output at runtime or a previous run? Because there is no time machine to get the locale from a call in the past :)
The ABAP statement SET COUNTRY may change the date format, the time format (since ABAP 7.02) and the number format, but there's officially no reverse way to get the current active country code (as you quoted in your question, based on the ABAP documentation). It's quite logical because, for instance, the current number format may be different from the current country code, so it's better to test the directly the kind of format you need to use, as follows.
To detect the current date format, use the official way which returns a character, whose possible values are described in the ABAP documentation of Date Formats):
DATA(current_date_format) = CL_ABAP_DATFM=>GET_DATFM( ).
To detect the current time format, use the official way which returns a character:
DATA(current_time_format) = CL_ABAP_TIMEFM=>GET_ENVIRONMENT_TIMEFM( ).
It returns one of the following values, with an example value corresponding to noon + 5 minutes and 10 seconds (the example value is given if it's output on at least 11 characters):
0 : 12:05:10 (0 to 23)
1 : 12:05:10 PM (0 to 12)
2 : 12:05:10 pm (0 to 12)
3 : 00:05:10 PM (0 to 11)
4 : 00:05:10 pm (0 to 11)
To detect the current number format, based on the idea from #Gert Beukema, you may do as follows:
DATA(current_number_format) = SWITCH usr01-dcpfm(
|{ 1000 NUMBER = ENVIRONMENT DECIMALS = 1 }|
WHEN '1.000,00' THEN ' '
WHEN '1,000.00' THEN 'X'
WHEN '1 000,00' THEN 'Y' ).
NB: the values , X and Y which are returned by this expression are the same values as those used in tables-columns USR01-DCPFM and T005X-XDEZP.

Formatting duration for display

In a SAP database there are values formatted as PxDTyH where x is the number of days and y is the number of hours. A value like P2DT0H is 2 days + 0 hours. I can see that via SE16:
Unfortunately, this is exactly displayed like that to the user, "3" corresponds to the index in the database (not seen in the screenshot above).
I'd like to see it displayed
without the index (changing the options "show keys within drop-down lists" did not have an effect)
instead of the technical name P2DT0H I'd like to see "2 days and 0 hours" (or similar)
Is there a way to process the data before it gets displayed in the combo box? The developers can't change the format in the database because it would change the API.
FYI: I'm just a tester, I don't know how to code in ABAP, but from knowledge of other programming languages, I'd say that the data can be converted before it's displayed. I don't need a fully-fledged answer, just a pointer to a SAP hook or event which enables writing a conversion function.
Probably, conversion routines can be an option for you. What you should do is to:
Take your domain (which is used for PxDTyH values) or create new one specially for this.
Create FM with name CONVERSION_EXIT_%NAME%_OUTPUT, and put conversion logic in there. Mandatory parameters INPUT and OUTPUT should exist.
Enter the %NAME% into Convers.routine field in domain properties.
Enable Check conversion exits checkbox in user parameters.
More info is here.

How to change the variable length in Progress?

I'm pretty new to progress and I want to ask a question.
How do I change variable (string) length in runtime?
ex.
define variable cname as char.
define variable clen as int.
cname= "".
DO cnts = 1 TO 5.
IF prc[cnts] <> "" THEN DO:
clen = clen + LENGTH(prc[cnts]).
cname = cname + prc[cnts].
END.
END.
Put cname format '???' at 1. /here change variable length/
Thanks for the reply
If the PUT statement is what you want to change, then
PUT UNFORMATTED cname.
will write the entire string out without having to worry about the length of the FORMAT phrase.
If you need something formatted, then
PUT UNFORMATTED STRING(cname, fill("X", clen)).
will do what you want. Look up the "STRING()" function in the ABL Ref docs.
In Progress 4GL all data is variable length.
This is one of the big differences between Progress and lots of other development environments. (And in my opinion a big advantage.)
Each datatype has a default format, which you can override, but that is only for display purposes.
Display format has no bearing on storage.
You can declare a field with a display format of 3 characters:
define variable x as character no-undo format "x(3)".
And then stuff 60 characters into the field. Progress will not complain.
x = "123456789012345678901234567890123456789012345678901234567890".
It is extremely common for 4gl application code to over-stuff variables and fields.
(If you then use SQL-92 to access the data you will hear much whining and gnashing of teeth from your SQL client. This is easily fixable with the "dbtool" utility.)
You change the display format when you define something:
define variable x as character no-undo format "x(30)".
or when you use it:
put x format "x(15)".
or
display x format "x(43)".
(And in many other ways -- these are just a couple of easy examples.)
Regardless of the display format the length() function will report the actual length of the data.

How to display comparisons with set expression?

My dataset has WeekEndingDate and Sales. I am displaying a straight table with all the selected data but I need to have another table showing the following:
Sales (other columns...)
First week : 1,000
Last week : 1,350
Difference : 350
Difference %: 35%
My questions:
a) Can I have the above in one chart/table, or I need 4 different charts showing columns filtered by set expressions?
b) My strategy is having 2 variables (vMinWeek and vMaxWeek), and using them in set expressions. Is that the best route?
c) My set expressions (below) are not working - they sum the whole data set. Would you please help me understanding why?
=max ({$<WeekEndingDate={'$(vMinWeek)'}>} Sales)
Thank you for your help!
Mara
I think the reason your set isn't working is that your WeekEnd date is formatted as a date and your variable is formatted as a number.
The trick with Set Analysis is always to think what you would have to type in a list box to get to your answer. So even though QlikView stores WeekEnd 2014/08/18 as 41869 you can't type 41869 in the WeekEnd list box and get back that date. So I would make your variables of the form =date(min(WeekEnd)).
The second part of your question; getting the table you want. I would do like this. I make a loose table with the dimension values, dual is so that it sorts correctly in the chart we are going to build.
load dual(D,N) as DIM inline [
D,N
First Week,1
Last Week,2
Difference,3
Dif %,4
];
I like defining my variables in the script as well, so I would do this.
set vFirstWeek='=date(min(WeekEnd))';
set vLastWeek='=date(max(WeekEnd))';`
Then when building the straight table we use the dimension as DIM but because DIM isn't connected to anything we have to do some work to get it to display values that fit those dimension values. The num(,'# ##0') is just to format the % differently from the sums. For this to work the number format in the Number tab of the chart must be set to Expression Default.
if(DIM='First Week',num(sum({<WeekEnd={'$(vFirstWeek)'}>} Sales),'# ##0'),
if(DIM='Last Week',num(sum({<WeekEnd={'$(vLastWeek)'}>} Sales),'# ##0'),
if(DIM='Difference',num(sum({<WeekEnd={'$(vFirstWeek)'}>} Sales)-sum({<WeekEnd={'$(vLastWeek)'}>} Sales),'# ##0'),
if(DIM='Dif %',num((sum({<WeekEnd={'$(vFirstWeek)'}>} Sales)-sum({<WeekEnd={'$(vLastWeek)'}>} Sales))/sum({<WeekEnd={'$(vLastWeek)'}>} Sales),'0.00%')))))

Format date like M/D/Y

I got a date of the type SYDATUM and wondering how to format it in a format like m/d/y.
I've found some snippets on the web, but they were not really helpful.
-thanks yor your help.
You should be more specific - what exactly do you want to do with the date (use type D internally, it's shorter and does the same thing).
Do you want to WRITE it to a list screen? Use the formatting options described in the documentation and online help:
WRITE l_my_date MM/DD/YYYY.
Do you want to convert it to a text variable? Very similar:
WRITE l_my_date TO l_my_text MM/DD/YYYY.
To set the date format in a SAPscript form, see the SET DATE MASK command.
To print the formatted date in a SmartForm, use the WRITE command and a temporary variable (yes, ugly, I know...)
Most controls (ALV Grid for example) should take care of the format automatically.
However - be careful when hard-coding the format into your application. Usually you don't have to do this because the system automatically uses the format specified in the user master data. This ensures that every user will see the date formatted according to their locale settings.
Normally it's better to export the date into the plant level country specific date format:
if w_country is initial.
select single LAND1
from T001W
into w_country
where WERKS eq w_the_plant.
endif.
SET COUNTRY w_country.
write w_the_date to w_export.
for example 03/04/2002 could be different date in different country.
You can try the keyword TRANSLATE. Alternatively suggest you could have a look at this link