ABAP - XCO Systemfelder
Gibt es für SY bzw. SYST auch eine Alternative in der XCO Bibliothek in ABAP Cloud? Einen Blick ist sie auf jeden Fall wert.
Inhaltsverzeichnis
Die XCO Klassen sind Hilfsklassen die verschiedene Funktionen des Alltags gebündelt unter einer öffentlichen API zur Verfügung stellen. Weitere Informationen und eine Übersicht über die XCO Bibliotheken findest du auf der Übersichtsseite.
Einleitung
In diesem Artikel schauen wir uns die Bibliothek im Bereich der Systemfelder an und welche Informationen bereits vorhanden sind und was wir vom Standard noch geschenkt bekommen. Wir verwenden dazu die XCO_CP=>SY, in diesem Objekt stecken alle wichtigen Informationen und Objekte.
User
Das Lesen der User ID wird über den USER durchgeführt. Aktuell besitzt das Interface nur ein Attribut NAME und hat damit den gleichen Umfang wie SY-UNAME.
" Classic
DATA(user_id) = sy-uname.
" XCO
user_id = xco_cp=>sy->user( )->name.
Sprache
Möchtest du an die aktuelle Sprache des angemeldeten Benutzers kommen, kannst du das LANGUAGE Objekt verwenden. Hier kommst du über VALUE an die klassische SAP Sprache (D = Deutsch, E = Englisch).
" Classic
DATA(language_sap) = sy-langu.
" XCO
language_sap = xco_cp=>sy->language( )->value.
Zusätzlich stehen weitere Informationen zur Verfügung, wie ein Kurztext, die Beschreibung und die Kennung im ISO Format. Das spart das Lesen aus den Standard Core Data Services.
DATA(short_name) = xco_cp=>sy->language( )->get_name( ).
DATA(long_name) = xco_cp=>sy->language( )->get_long_text_description( ).
DATA(language_iso) = xco_cp=>sy->language( )->as( xco_cp_language=>format->iso_639 ).
Hier die Ausgabe der Informationen in die Konsole um die Ergebnisse prüfen zu können.
Meldung
In vielen Szenarien wird eine Nachrichtenausgabe in die Message Variablen der SY Struktur übernommen. Diese kannst du dann über die verschiedenen Felder abrufen, um an alle Informationen zu gelangen.
" Classic
DATA(message_id) = sy-msgid.
DATA(message_number) = sy-msgno.
DATA(message_type) = sy-msgty.
DATA(message_v1) = sy-msgv1.
Das Sammeln der Informationen ist aber immer Entwicklungslastig, die einzelnen Informationen zu mappen oder wiederverwendbare Funktionen zu schreiben. Über das MESSAGE Objekt, werden die Informationen eingesammelt und als Objekt zur Verfügung gestellt. Über das Objekt können wir auf VALUE zugreifen, welches eine Struktur vom Typ SYMSG ist.
" XCO
DATA(xco_message) = xco_cp=>sy->message( ).
message_id = xco_message->value-msgid.
message_number = xco_message->value-msgno.
message_type = xco_message->value-msgty.
message_v1 = xco_message->value-msgv1.
Das Message Objekt und das Handling damit, werden wir uns in einem zusätzlichen Artikel anschauen.
Datum
Das DATE Objekt unterstützt einige mehr Funktionen, deshalb teilen wir diesen Abschnitt in mehrere Teile auf, um verschiedene Bestandteile des Objekts zu betrachten.
Lesen
Das einfache Lesen des aktuellen Datums ist nicht ganz so einfach. Sobald wir Zugriff auf das DATE Objekt haben, müssen wir das Format für die Ausgabe definieren. Hier gibt es leider keinen Default Parameter, sondern wir müssen zuerst einen Formatter übergeben.
" Classic
DATA(system_date) = sy-datlo.
" XCO
system_date = xco_cp=>sy->date( )->as( xco_cp_time=>format->abap )->value.
Format
Über die Methode AS können wir weitere Formatter mitgeben, um unterschiedliche Ausgaben zu erhalten. Weitere Filter findest du hier im Beispiel.
DATA(iso_8601_basic) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_basic )->value.
DATA(iso_8601_extended) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value.
Schauen wir uns die Inhalte der Objekte im Debugger an, da die Konsole sonst den Datentyp verändern würde. Die verschiedenen Formate können für die Ausgabe verwendet werden, da das Ergebnis als String (Objekt) zurückgegeben wird.
Bestandteile
Möchtest du nur einen Bestandteil des Datums lesen, stehen über die Attribute YEAR, MONTH und DAY die Informationen zur Verfügung.
DATA(date_year) = xco_cp=>sy->date( )->year.
DATA(date_month) = xco_cp=>sy->date( )->month.
DATA(date_day) = xco_cp=>sy->date( )->day.
Berechnung
Du findest ebenfalls im Objekt einige Methoden, um mit dem Datum zu rechnen. Dazu stehen die folgenden Methoden zur Verfügung:
- ADD - Addieren zum aktuellen Datum
- SUBTRACT - Subtrahieren zum aktuellen Datum
- OVERWRITE - Überschreiben einzelner Bestandteile
Die Methoden übernehmen das Jahr, Monat oder Tag, je nachdem mit was du Rechnen willst oder welches Feld du überschreiben möchtest.
DATA(last_week) = xco_cp=>sy->date( )->subtract( iv_day = 7 )->as( xco_cp_time=>format->abap )->value.
DATA(year_2000) = xco_cp=>sy->date( )->overwrite( iv_year = 2000 )->as( xco_cp_time=>format->abap )->value.
Im Beispiel oben nehmen wir das aktuelle Datum und ziehen 7 tage (eine Woche) vom Datum ab. Im zweiten Beispiel setzen wir das Jahr zurück auf 2000. Wie bei XCO üblich, kannst du die Aufrufe miteinander kombinieren.
Uhrzeit
Schauen wir uns die Uhrzeit bzw. das TIME Objekt einmal genauer an, dann gibt es auch hier fast alle Funktionen wie beim Datum. Wie ermittelst du die aktuelle Uhrzeit und gibst sie aus, dazu ein kleines Beispiel:
" Classic
DATA(system_time) = sy-timlo.
" XCO
system_time = xco_cp=>sy->time( )->as( xco_cp_time=>format->abap )->value.
Hinweis: Für weitere Details findest du im Kapitel Datum die relevanten Funktionen für die Uhrzeit. Bei den Bestandteilen kannst du hier aber auf Stunde, Minute und Sekunde zugreifen.
Moment
Das MOMENT Objekt ist eine Kombination aus Datum und Uhrzeit und kann zu einem Zeitstempel kombiniert werden. Das Objekt verwaltet beide Informationen und diese können entsprechend kombiniert und berechnet werden.
Erzeugung
Wie erzeugen wir eingentlich ein MOMENT Objekt? Im Grunde wie die anderen Objekte bisher. Allerdings haben wir uns einen Punkt noch nicht angeschaut, im Standard gibt es die User- und die UTC-Zeit. Wenn du dir das Objekt generieren lässt, dann bekommst du immer ein Objekt in Userzeit. Dazu ein Beispiel, wie du die unterschiedlichen Objekte in ABAP erzeugen kannst.
DATA(moment_user) = xco_cp=>sy->moment( xco_cp_time=>time_zone->user ).
DATA(moment_utc) = xco_cp=>sy->moment( xco_cp_time=>time_zone->utc ).
Formatierung
Hier haben wir die gleichen Formatter, wie für Datum und Uhrzeit. Führen wir dazu einmal die Ausgabe der drei gängigen Formate durch.
DATA(output_format_abap) = moment_user->as( xco_cp_time=>format->abap )->value.
DATA(output_format_basic) = moment_user->as( xco_cp_time=>format->iso_8601_basic )->value.
DATA(output_format_extended) = moment_user->as( xco_cp_time=>format->iso_8601_extended )->value.
Im Anschluss schauen wir uns das Ergebnis im Debugger an, um die Typen und Formatierung zu prüfen.
Berechnung
Eine Berechnung stehen auch hier die Methoden ADD, SUBTRACT und OVERWRITE zur Verfügung, die zur Anpassung des Objekts verwendet werden können. Hier können alle Informationen vom Datum bis zur Uhrzeit übergeben werden.
Objekte
Aus einem MOMENT Objekt lassen sich auch verschiedene Objekte generieren, zum Beispiel ein Timestamp, ein Datum oder eine Uhrzeit. DATE und TIME sind jeweils Attribute am Objekt, die die Informationen enthalten. Für den Timestamp gibt es die Methode GET_UNIX_TIMESTAMP, die ein entsprechendes Objekt zurückgibt.
Vergleich
Du kannst zwei Momente miteinander vergleichen, dazu stehen dir am Objekt zahlreiche Methoden zur Verfügung. Dazu eine kurze Auflistung der Methoden und ihre Funktion:
- IS_BEFORE - Prüfung, ob das Objekt vor dem übergebenen Moment liegt.
- IS_AFTER - Prüfung, ob das Objekt nach dem übergebenen Moment liegt.
- IS_NOT_BEFORE und IS_NOT_AFTER - Prüft das Gegenteil der anderen beiden Methoden
Dazu erzeugen wir das folgende Beispiel und vergleichen einen Moment in der Zukunft (plus ein Tag) mit dem aktuellen Moment unseres Users. Ist soweit alles korrekt, dann wird der Satz in die Konsole ausgegeben.
DATA(future) = xco_cp=>sy->moment( )->add( iv_day = 1 ).
IF moment_user->is_before( future ).
out->write( `The future is not here ...` ).
ENDIF.
Intervalle
Mit den Methoden INTERVAL_FROM und INTERVAL_TO erhältst du ein Intervall Objekt und kannst mit der Methode CONTAINS prüfen, ob ein anderer Moment zwischen den beiden Momenten liegt. Im folgenden Beispiel erzeugen wir ein Intervall zwischen Jetzt und Morgen und prüfen, ob die UTC Zeit dazwischen liegt.
DATA(from_moment_to_future) = moment_user->interval_to( future ).
out->write( from_moment_to_future->contains( moment_utc ) ).
Zusammenfassung
Schauen wir uns daher noch einmal an, welche Felder wir aus der SYST heute bereits ablösen können. Grundsätzlich steht dir neben den verschiedenen Feldern auch einiges an Zusatzfunktionen zur Verfügung, um die Informationen aufzubereiten, zu berechnen oder zu konvertieren.
- SY-UNAME
- SY-DATUM, SY-DATLO
- SY-UZEIT, SY-TIMLO
- SY-LANGU
- SY-MSGID, SY-MSGNO, SY-MSGTY, SY-MSGV1, SY-MSGV2, SY-MSGV3, SY-MSGV4
- TIMESTAMP
Vollständiges Beispiel
Das vollständige Beispiel findest du bei uns im GitHub Repository, dort auch die anderen Beispiele aus dem Bereich XCO Bibliothek. Alle aktuellen Änderungen findest du in diesem Commit. Dazu noch einmal die ausführbare Klasse aus diesem Artikel.
CLASS zcl_bs_demo_xco_syst DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
METHODS user_name
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS language
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS date
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS time
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS system_message
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS moment
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_xco_syst IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
user_name( out ).
language( out ).
date( out ).
time( out ).
system_message( out ).
moment( out ).
ENDMETHOD.
METHOD user_name.
" Classic
DATA(user_id) = sy-uname.
out->write( user_id ).
" XCO
user_id = xco_cp=>sy->user( )->name.
out->write( user_id ).
ENDMETHOD.
METHOD language.
" Classic
DATA(language_sap) = sy-langu.
out->write( language_sap ).
" XCO
language_sap = xco_cp=>sy->language( )->value.
out->write( language_sap ).
DATA(short_name) = xco_cp=>sy->language( )->get_name( ).
out->write( short_name ).
DATA(long_name) = xco_cp=>sy->language( )->get_long_text_description( ).
out->write( long_name ).
DATA(language_iso) = xco_cp=>sy->language( )->as( xco_cp_language=>format->iso_639 ).
out->write( language_iso ).
ENDMETHOD.
METHOD date.
" Classic
DATA(system_date) = sy-datlo.
out->write( system_date ).
" XCO
system_date = xco_cp=>sy->date( )->as( xco_cp_time=>format->abap )->value.
out->write( system_date ).
DATA(iso_8601_basic) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_basic )->value.
out->write( iso_8601_basic ).
DATA(iso_8601_extended) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value.
out->write( iso_8601_extended ).
DATA(date_year) = xco_cp=>sy->date( )->year.
DATA(date_month) = xco_cp=>sy->date( )->month.
DATA(date_day) = xco_cp=>sy->date( )->day.
out->write( date_year ).
out->write( date_month ).
out->write( date_day ).
DATA(last_week) = xco_cp=>sy->date( )->subtract( iv_day = 7 )->as( xco_cp_time=>format->abap )->value.
out->write( last_week ).
DATA(year_2000) = xco_cp=>sy->date( )->overwrite( iv_year = 2000 )->as( xco_cp_time=>format->abap )->value.
out->write( year_2000 ).
ENDMETHOD.
METHOD time.
" Classic
DATA(system_time) = sy-timlo.
out->write( system_time ).
" XCO
system_time = xco_cp=>sy->time( )->as( xco_cp_time=>format->abap )->value.
out->write( system_time ).
ENDMETHOD.
METHOD system_message.
MESSAGE w001(zbs_demo_xco) WITH 'Method' 'Message' INTO DATA(dummy_message).
" Classic
DATA(message_id) = sy-msgid.
DATA(message_number) = sy-msgno.
DATA(message_type) = sy-msgty.
DATA(message_v1) = sy-msgv1.
out->write( message_id ).
out->write( message_number ).
out->write( message_type ).
out->write( message_v1 ).
" XCO
DATA(xco_message) = xco_cp=>sy->message( ).
message_id = xco_message->value-msgid.
message_number = xco_message->value-msgno.
message_type = xco_message->value-msgty.
message_v1 = xco_message->value-msgv1.
out->write( message_id ).
out->write( message_number ).
out->write( message_type ).
out->write( message_v1 ).
ENDMETHOD.
METHOD moment.
DATA(moment_user) = xco_cp=>sy->moment( xco_cp_time=>time_zone->user ).
DATA(moment_utc) = xco_cp=>sy->moment( xco_cp_time=>time_zone->utc ).
DATA(output_format_abap) = moment_user->as( xco_cp_time=>format->abap )->value.
DATA(output_format_basic) = moment_user->as( xco_cp_time=>format->iso_8601_basic )->value.
DATA(output_format_extended) = moment_user->as( xco_cp_time=>format->iso_8601_extended )->value.
out->write( output_format_abap ).
out->write( output_format_basic ).
out->write( output_format_extended ).
DATA(future) = xco_cp=>sy->moment( )->add( iv_day = 1 ).
IF moment_user->is_before( future ).
out->write( `The future is not here ...` ).
ENDIF.
DATA(from_moment_to_future) = moment_user->interval_to( future ).
out->write( from_moment_to_future->contains( moment_utc ) ).
ENDMETHOD.
ENDCLASS.
Fazit
Für einige Systemfelder gibt es bereits eine Alternative, die heute schon verwendet werden kann. In einigen Bereichen bietet die Klasse bereits Mehrwerte, wenn es um die Aufbereitung der Informationen geht und sollte in einem nächsten Projekt von dir zum Einsatz kommen.