[ABAP] SALV-Table: Darstellung (Ausgabeformat) einer Spalte über einen Konvertierungs-Exit anpassen

Beispiel 1: Zeitstempel formatieren (==TSTMP)

DATA: o_alv TYPE REF TO cl_salv_table.

DATA: it_tab TYPE ...

cl_salv_table=>factory( IMPORTING
                          r_salv_table = o_alv
                        CHANGING
                          t_table      = it_tab ).

* Der Inhalt der Spalte 'TIMESTAMP' soll anstelle des zusammengesetzten Standartformates für den p-Datentyp
* eine andere Darstellung, getrennt nach Datum und Uhrzeit, bekommen
* '20180101120101,1234567' -> '01.01.2018 12:01:01'
*
* Dazu wird der vorhandene Konvertierungs-Exit CONVERSION_EXIT_TSTMP_INPUT und CONVERSION_EXIT_TSTMP_OUTPUT
* aufgerufen, indem man das Kürzel '==TSTMP' (mittlere Buchstaben im Bezeichner CONVERSION_EXIT_... ) angibt.
*
* alle vorhandenen Konvertierungs-Exits: Transaktion SE37 -> Funktionsbaustein "CONVERSION_EXIT_*" -> Lupe
* Tabelle: TFDIR
o_alv->get_columns( )->get_column( 'TIMESTAMP' )->set_edit_mask( '==TSTMP' ).

o_alv->display( ).

Beispiel 2: Nachkommastellen abschneiden (==DEC0)

SELECT FROM marc
  FIELDS matnr, werks, eisbe
  INTO TABLE @DATA(it_marc)
  UP TO 100 ROWS.

IF sy-subrc = 0.
  TRY.
*   SALV-Table
      DATA: o_salv TYPE REF TO cl_salv_table.

      cl_salv_table=>factory( IMPORTING r_salv_table = o_salv
                              CHANGING  t_table      = it_marc ).

*   Grundeinstellungen
      o_salv->get_functions( )->set_all( abap_true ).
      o_salv->get_columns( )->set_optimize( abap_true ).
      o_salv->get_display_settings( )->set_list_header( 'MARC' ).
      o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
      o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>row_column ).

*   Spaltenüberschriften: technischer Name und Beschreibungstexte, Short Text und Medium Text leer lassen für Autosize
      LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
        DATA(o_col) = <c>-r_column.
        o_col->set_short_text( || ).
        o_col->set_medium_text( || ).
        o_col->set_long_text( |{ o_col->get_long_text( ) }| ).
      ENDLOOP.

* Sicherheitsbestand --> Nachkommastellen in der Darstellung abschneiden
      o_salv->get_columns( )->get_column( 'EISBE' )->set_edit_mask( value = '==DEC0' ).

      o_salv->display( ).
    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.
ENDIF.

Links

[ABAP] OADate (Ole Automation Date) in Zeitstempel (timestamp) umrechnen

* https://stackoverflow.com/questions/43519005/how-to-convert-java-date-to-oadate-or-vice-versa
* https://msdn.microsoft.com/de-de/library/system.datetime.tooadate(v=vs.110).aspx

* Zeitstempel im OADate-Format
DATA: lv_oadate TYPE decfloat34 VALUE '43013.765983796296296000'. " 05.10.2017 18:23:01
*DATA: lv_oadate TYPE decfloat34 VALUE '42909.777881944444444000'. " 23.06.2017 18:40:09
*DATA: lv_oadate TYPE decfloat34 VALUE '42370.000717592592592593'. " 01.01.2016 00:01:02
* Basisdatum für OADate ist der 30.12.1899
DATA: lv_basedate TYPE d VALUE '18991230'.

DATA: lv_oadays TYPE i.
DATA: lv_oatime TYPE decfloat34.
DATA: lv_hour TYPE decfloat34.
DATA: lv_min TYPE decfloat34.
DATA: lv_sec TYPE decfloat34.

DATA: lv_d TYPE d.
DATA: lv_t TYPE t.
DATA: lv_datetime TYPE timestamp.

* Vorkommateil: Tage seit Basisdatum
lv_oadays = trunc( lv_oadate ).
* Nachkommateil: Tageszeit
lv_oatime = lv_oadate - CONV decfloat34( lv_oadays ).
* Nachkommateil: Stunden
lv_hour = lv_oatime * 24.
* Nachkommateil: Minuten
lv_min = ( lv_hour - trunc( lv_hour ) ) * 60.
* Nachkommateil: Sekunden
lv_sec = round( val = ( ( lv_min - trunc( lv_min ) ) * 60 ) dec = 0 ).

* Datum: Basisdatum + Tage des Vorkommateils
lv_d = lv_basedate + lv_oadays.
* Uhrzeit
lv_t = |{ CONV string( trunc( lv_hour ) ) WIDTH = 2 ALPHA = IN }{ CONV string( trunc( lv_min ) ) WIDTH = 2 ALPHA = IN }{ CONV string( trunc( lv_sec ) ) WIDTH = 2 ALPHA = IN }|.

* Datum und Uhrzeit in einem Zeitstempelobjekt zusammenfassen
CONVERT DATE lv_d TIME lv_t INTO TIME STAMP lv_datetime TIME ZONE 'UTC'.

WRITE: / '     OADate:', lv_oadate.
WRITE: / 'Zeitstempel:', lv_datetime TIME ZONE 'UTC'.

[ABAP] Zeitstempel (timestamp) in OADate (Ole Automation Date) umrechnen

* https://stackoverflow.com/questions/43519005/how-to-convert-java-date-to-oadate-or-vice-versa
* https://msdn.microsoft.com/de-de/library/system.datetime.tooadate(v=vs.110).aspx

* Zeitstempel mit Datum und Uhrzeit
*DATA: lv_datetime TYPE timestamp VALUE '20171005182301'. " 43013.765983796296296000
*DATA: lv_datetime TYPE timestamp VALUE '20170623184009'. " 42909.777881944444444000
DATA: lv_datetime TYPE timestamp VALUE '20160101000102'. " 42370.000717592592592593
* Basisdatum für OADate ist der 31.12.1899
DATA: lv_ts_base TYPE timestamp VALUE '18991231000000'.

DATA: lv_d TYPE d.
DATA: lv_t TYPE t.

DATA: lv_oadays TYPE i.

DATA: lv_hour TYPE decfloat34.
DATA: lv_min TYPE decfloat34.
DATA: lv_sec TYPE decfloat34.

DATA: lv_oadate TYPE decfloat34.

* Timestamp in Date und Time aufsplitten
CONVERT TIME STAMP lv_datetime TIME ZONE 'UTC' INTO DATE lv_d TIME lv_t.

* Zeitdifferenz zwischen Zeitstempel und Basisdatum in Sekunden
DATA(lv_diff_sec) = cl_abap_tstmp=>subtract( tstmp1 = lv_datetime
                                             tstmp2 = lv_ts_base ).

* Vorkommateil: Zeitdifferenz zwischen Zeitstempel und Basisdatum in Tagen
lv_oadays = lv_diff_sec / 86400.
* Nachkommateil: Stunden
lv_hour = CONV decfloat34( lv_t+0(2) ) / 24.
* Nachkommateil: Minuten
lv_min = CONV decfloat34( lv_t+2(2) ) / 1440.
* Nachkommateil: Sekunden
lv_sec = CONV decfloat34( lv_t+4(2) ) / 86400.

* OADate zusammenrechnen: Vorkommateil + Nachkommateil
lv_oadate = lv_oadays + lv_hour + lv_min + lv_sec.

WRITE: / 'Zeitstempel:', lv_datetime TIME ZONE 'UTC'.
WRITE: / '     OADate:', lv_oadate.

[ABAP] UTC-Zeit (TIMESTAMP) in Datum (d) und Uhrzeit (t) splitten

DATA: lv_date TYPE d.
DATA: lv_time TYPE t.
DATA: lv_utc TYPE timestamp.

GET TIME STAMP FIELD lv_utc.

* Zeitzohne bleibt UTC, Timestamp wird also ohne Umrechnung der Zone gesplittet
CONVERT TIME STAMP lv_utc TIME ZONE 'UTC' INTO DATE lv_date TIME lv_time.

WRITE: / |UTC: { lv_utc TIMESTAMP = USER }|.
WRITE: / |UTC-Datum: { lv_date DATE = USER }|.
WRITE: / |UTC-Zeit: { lv_time TIME = USER }|.

[ABAP] UTC-Zeit (TIMESTAMP) in Systemzeit wandeln

DATA: lv_utc TYPE timestamp.
DATA: lv_date TYPE d.
DATA: lv_time TYPE t.

START-OF-SELECTION.

  GET TIME STAMP FIELD lv_utc.

  TRY.
      cl_abap_tstmp=>systemtstmp_utc2syst( EXPORTING
                                             utc_tstmp = lv_utc
                                           IMPORTING
                                             syst_date = lv_date
                                             syst_time = lv_time  ).

      WRITE: / |UTC: { lv_utc TIMESTAMP = USER }|.
      WRITE: / |System-Datum: { lv_date DATE = USER }|.
      WRITE: / |System-Zeit: { lv_time TIME = USER }|.

    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

[ABAP] Systemzeit in UTC-Zeit (TIMESTAMP) wandeln

DATA: lv_utc TYPE timestamp.
DATA: lv_date TYPE d.
DATA: lv_time TYPE t.

START-OF-SELECTION.

  lv_date = sy-datum.
  lv_time = sy-uzeit.

  TRY.
      cl_abap_tstmp=>systemtstmp_syst2utc( EXPORTING
                                             syst_date = lv_date
                                             syst_time = lv_time
                                           IMPORTING
                                             utc_tstmp = lv_utc ).

      WRITE: / |UTC: { lv_utc TIMESTAMP = USER }|.
      WRITE: / |System-Datum: { lv_date DATE = USER }|.
      WRITE: / |System-Zeit: { lv_time TIME = USER }|.

    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

[ABAP] string-Formatierungen mit String-Templates

* ab V7.31
* http://zevolving.com/2013/07/abap-string-templates-new-feature-in-abap-731/

* Hinweis: String-Templates funktionieren nur Programmen bei denen die Unicodeprüfung aktiv ist!
* Z.B. kommt es in Modulpool-Programmen zu Fehlern beim kompilieren des Codes und der Compiler moniert die '|'-Symbole

DATA: text TYPE string VALUE 'Text'.
DATA: atext TYPE string VALUE '012345'.
DATA: num TYPE p DECIMALS 3 VALUE '-123.45'.

* Case
WRITE: / |RAW:   { text CASE = RAW }|.   " Text
WRITE: / |LOWER: { text CASE = LOWER }|. " text
WRITE: / |UPPER: { text CASE = UPPER }|. " TEXT

* Align
WRITE: / |LEFT:   ->{ text WIDTH = 20 ALIGN = LEFT }<--|.   " >Text                <
WRITE: / |RIGHT:  ->{ text WIDTH = 20 ALIGN = RIGHT }<--|.  " >                Text<
WRITE: / |CENTER: ->{ text WIDTH = 20 ALIGN = CENTER }<--|. " >        Text        <

* Padding, Auffüllen mit definiertem Zeichen
WRITE: / |PAD: { text ALIGN = LEFT WIDTH = 20 PAD = '_' }|.   " Text________________
WRITE: / |PAD: { text ALIGN = RIGHT WIDTH = 20 PAD = '_' }|.  " ________________Text
WRITE: / |PAD: { text ALIGN = CENTER WIDTH = 20 PAD = '_' }|. " ________Text________

* führende Nullen hinzufügen, ersetzt FUBA 'CONVERSION_EXIT_ALPHA_INPUT'
WRITE: / |ALPHA: { atext WIDTH = 20 ALPHA = IN }|. " 00000000000000012345
* führende Nullen entfernen, ersetzt FUBA 'CONVERSION_EXIT_ALPHA_OUTPUT'
WRITE: / |ALPHA: { atext ALPHA = OUT }|.           " 12345

* Zahlen 1
WRITE: / |RAW:         { num NUMBER = RAW }|.         " -123.45
WRITE: / |USER:        { num NUMBER = USER }|.        " -123,45
WRITE: / |ENVIRONMENT: { num NUMBER = ENVIRONMENT }|. " -123,45

* Zahlen 2
WRITE: / |SCIENTIFIC:                   { num STYLE = SCIENTIFIC }|.                   " -1.2345E+02
WRITE: / |SCIENTIFIC_WITH_LEADING_ZERO: { num STYLE = SCIENTIFIC_WITH_LEADING_ZERO }|. " -0.12345E+03
WRITE: / |SCALE_PRESERVING_SCIENTIFIC:  { num STYLE = SCALE_PRESERVING_SCIENTIFIC }|.  " -1.2345E+0002
WRITE: / |ENGINEERING:                  { num STYLE = ENGINEERING }|.                  " -123.45E+00

* Datumsformat
WRITE: / |RAW:         { sy-datum DATE = RAW }|.         " 20160705
WRITE: / |ISO:         { sy-datum DATE = ISO }|.         " 2016-07-05
WRITE: / |USER:        { sy-datum DATE = USER }|.        " 05.07.2016
WRITE: / |ENVIRONMENT: { sy-datum DATE = ENVIRONMENT }|. " 05.07.2016

* Uhrzeitformat
WRITE: / |RAW:         { sy-uzeit TIME = RAW }|.         " 102336
WRITE: / |ISO:         { sy-uzeit TIME = ISO }|.         " 10:23:36
WRITE: / |USER:        { sy-uzeit TIME = USER }|.        " 10:23:36
WRITE: / |ENVIRONMENT: { sy-uzeit TIME = ENVIRONMENT }|. " 10:23:36

* Timestampformat
DATA: lv_tsl TYPE timestampl.
* Zeitstempel lang
GET TIME STAMP FIELD lv_tsl.
WRITE: / |SPACE:       { lv_tsl TIMESTAMP = SPACE }|.       " 2016-07-05 08:23:36.0908600
WRITE: / |ISO:         { lv_tsl TIMESTAMP = ISO }|.         " 2016-07-05T08:23:36,0908600
WRITE: / |USER:        { lv_tsl TIMESTAMP = USER }|.        " 05.07.2016 08:23:36,0908600
WRITE: / |ENVIRONMENT: { lv_tsl TIMESTAMP = ENVIRONMENT }|. " 05.07.2016 08:23:36,0908600

* ABAP Serialization XML (axXML)
WRITE: / |XML: { lv_tsl XSD = YES }|. " 20160705082336.09086

[ABAP] Mit Zeitstempel rechnen

Variante 1 (cl_abap_tstmp)

DATA: l_ts TYPE timestamp.
DATA: l_ts_out TYPE timestamp.

GET TIME STAMP FIELD l_ts.

* 3600s zum Zeitstempel hinzurechnen
l_ts_out = cl_abap_tstmp=>add( tstmp = l_ts
                               secs = 3600 ).

WRITE: / l_ts TIME ZONE sy-zonlo.
WRITE: / l_ts_out TIME ZONE sy-zonlo.

Variante 2 (cl_hrpad_date_computations)

* add_weeks_to_date             -> Addiert Anzahl Wochen zum Datum
* add_months_to_date            -> Addiert Anzahl Monate zum Datum
* add_years_to_date             -> Addiert Anzahl Jahre zum Datum
* subtract_weeks_from_date      -> Subtrahiert Anzahl Wochen vom Datum
* subtract_months_from_date     -> Subtrahiert Anzahl Monate vom Datum
* subtract_years_from_date      -> Subtrahiert Anzahl Jahre vom Datum
* get_weekday_number            -> Ermittelt Nummer des Wochentags
* get_weekday_number_shifted    -> Ermittelt Nummer des Wochentags (verschoben)
* get_first_day_calendar_week   -> Ermittelt den ersten Tag einer Kalenderwoche für best. Jahr
* get_last_weekday_number       -> Bestimmt Nummer des letzten Wochentags
* get_first_day_in_week         -> Ermittelt den ersten Tag einer Woche
* get_first_day_in_shifted_week -> Ermittelt den ersten Tag einer Woche (verschoben)
* get_first_day_previous_month  -> Ermittelt den ersten Tag im davorliegenden Monat
* get_week                      -> Ermittelt die Woche in der das Datum liegt (verschoben)
* get_shifted_week              -> Ermittelt die Woche in der das Datum liegt (verschoben)
* get_last_day_in_month         -> Berechnet den letzten Tag des laufenden Monats
* get_last_day_previous_month   -> Ermittelt den letzten Tag des davorliegenden Monats
* get_days_per_year             -> Ermittelt Anzahl der Tage pro Jahr

Variante 3 (cl_bs_period_toolset_basics)

* erster Tag des aktuellen Monats
DATA(lv_first_day) = cl_bs_period_toolset_basics=>get_first_day_in_month( iv_date = sy-datum ).
WRITE: / lv_first_day.

* erster Tag des vorherigen Monats
DATA(lv_first_day) = cl_bs_period_toolset_basics=>get_first_day_prev_month( iv_date = sy-datum ).
WRITE: / lv_first_day.

* letzter Tag des vorherigen Monats
DATA(lv_last_day) = cl_bs_period_toolset_basics=>get_last_day_prev_month( iv_date = sy-datum ).
WRITE: / lv_last_day.

* letzter Tag des aktuellen Monats
DATA(lv_last_day) = cl_bs_period_toolset_basics=>get_last_day_in_month( iv_date = sy-datum ).
WRITE: / lv_last_day.

* 60 Minuten zu Zeit und Datum hinzurechnen
cl_bs_period_toolset_basics=>add_minutes_to_date( EXPORTING
                                                    iv_date    = sy-datum
                                                    iv_time    = sy-uzeit
                                                    iv_minutes = 60
                                                  IMPORTING
                                                    ev_date    = DATA(lv_date_new)
                                                    ev_time    = DATA(lv_time_new) ).

WRITE: / lv_date_new, lv_time_new.

[ABAP] Datentypen für Zeitdarstellung und deren Verwendung

DATA: lv_dt TYPE d.           " Datum (YYYYMMDD)
DATA: lv_tm TYPE t.           " Zeit (HHMMSS)
DATA: lv_ts TYPE timestamp.   " Zeitstempel kurz (YYYYMMDDhhmmss)
DATA: lv_tsl TYPE timestampl. " Zeitstempel lang (YYYYMMDDhhmmss,mmmuuun)

* Systemzeit holen
lv_tm = sy-uzeit.

* Systemdatum holen
lv_dt = sy-datum.

* Zeitstempel kurz holen
GET TIME STAMP FIELD lv_ts.

* Zeitstempel lang holen
GET TIME STAMP FIELD lv_tsl.

* Zeit formatiert ausgeben
WRITE: / lv_dt MM/DD/YYYY.

* Datum formatiert ausgeben
WRITE: /(8) lv_tm USING EDIT MASK '__:__:__'.

* Zeitstempel kurz entsprechend der lokalen Zeitzone des Users ausgeben
WRITE: / lv_ts TIME ZONE sy-zonlo.

* Zeitstempel lang entsprechend der lokalen Zeitzone des Users ausgeben
WRITE: / lv_tsl TIME ZONE sy-zonlo.