System-Felder Migration: Praktische Vorher-Nachher-Beispiele für ABAP Cloud

Kategorie
ABAP Cloud
Veröffentlicht
Autor
Johannes

Die Migration von SY-Feldern zu ABAP Cloud APIs ist einer der häufigsten Schritte bei der Modernisierung von ABAP-Code. Dieser Artikel zeigt konkrete Vorher/Nachher-Beispiele für 15 häufige Anwendungsfälle, eine wiederverwendbare Utility-Klasse und typische Fallstricke.

Grundlagen zu SY-Feldern und ihren Alternativen findest du im Artikel System-Felder in ABAP Cloud: Alternativen zu SY-*.

Übersicht: Die Migration auf einen Blick

┌─────────────────────────────────────────────────────────────┐
│ Migration von SY-Feldern │
│ ─────────────────────────────────────────────────────────── │
│ │
│ 1. ATC ausführen → findet alle SY-* Probleme │
│ 2. Utility-Klasse anlegen → zentrale Ersetzung │
│ 3. Suchen & Ersetzen → systematisch migrieren │
│ 4. Unit Tests → Verhalten validieren │
│ │
│ ✅ SY-SUBRC, SY-TABIX, SY-DBCNT bleiben unverändert! │
└─────────────────────────────────────────────────────────────┘

Teil 1: 15 Vorher/Nachher-Beispiele

1. Benutzername (SY-UNAME)

" ❌ Classic ABAP - nicht Cloud-ready
DATA(lv_user) = sy-uname.
ls_document-created_by = sy-uname.
WHERE created_by = @sy-uname
" ✅ ABAP Cloud - direkte Migration
DATA(lv_user) = cl_abap_context_info=>get_user_technical_name( ).
ls_document-created_by = cl_abap_context_info=>get_user_technical_name( ).
WHERE created_by = @( cl_abap_context_info=>get_user_technical_name( ) )

2. Systemdatum (SY-DATUM)

" ❌ Classic ABAP
DATA(lv_today) = sy-datum.
IF ls_booking-flight_date < sy-datum.
" Abgelaufen
ENDIF.
" ✅ ABAP Cloud
DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
IF ls_booking-flight_date < cl_abap_context_info=>get_system_date( ).
" Abgelaufen
ENDIF.

3. Systemzeit (SY-UZEIT)

" ❌ Classic ABAP
DATA(lv_time) = sy-uzeit.
ls_log-logged_at_time = sy-uzeit.
" ✅ ABAP Cloud
DATA(lv_time) = cl_abap_context_info=>get_system_time( ).
ls_log-logged_at_time = cl_abap_context_info=>get_system_time( ).

4. UTC Timestamp (GET TIME STAMP)

" ❌ Classic ABAP
DATA: lv_timestamp TYPE timestamp.
GET TIME STAMP FIELD lv_timestamp.
" ✅ ABAP Cloud - besser lesbar und typsicher
DATA(lv_timestamp) = cl_abap_context_info=>get_system_timestamp( ).
" Hinweis: Rückgabetyp ist UTCLONG (empfohlen für Datenbank)

5. Anmeldesprache (SY-LANGU)

" ❌ Classic ABAP
SELECT SINGLE text FROM ztab_texts
WHERE langu = @sy-langu
INTO @DATA(lv_text).
" ✅ ABAP Cloud
SELECT SINGLE text FROM ztab_texts
WHERE langu = @( cl_abap_context_info=>get_user_language_abap_format( ) )
INTO @DATA(lv_text).

6. Zeitzone (SY-ZONLO)

" ❌ Classic ABAP
DATA(lv_timezone) = sy-zonlo.
CONVERT TIME STAMP lv_utc TIME ZONE sy-zonlo
INTO DATE lv_local_date TIME lv_local_time.
" ✅ ABAP Cloud
DATA(lv_timezone) = cl_abap_context_info=>get_user_time_zone( ).
CONVERT TIME STAMP lv_utc TIME ZONE cl_abap_context_info=>get_user_time_zone( )
INTO DATE lv_local_date TIME lv_local_time.

7. Mandant (SY-MANDT)

" ❌ Classic ABAP
DATA(lv_client) = sy-mandt.
lv_table_key = |{ sy-mandt }{ lv_id }|.
" ✅ ABAP Cloud
DATA(lv_client) = cl_abap_context_info=>get_client( ).
lv_table_key = |{ cl_abap_context_info=>get_client( ) }{ lv_id }|.

8. System-ID (SY-SYSID)

" ❌ Classic ABAP
IF sy-sysid = 'PRD'.
" Produktionssystem
ENDIF.
" ✅ ABAP Cloud
IF cl_abap_context_info=>get_system_id( ) = 'PRD'.
" Produktionssystem
ENDIF.

9. Audit-Logging mit Benutzer und Zeitstempel

" ❌ Classic ABAP
ls_audit_log = VALUE #(
user_name = sy-uname
log_date = sy-datum
log_time = sy-uzeit
client = sy-mandt
).
" ✅ ABAP Cloud - komplett migriert
ls_audit_log = VALUE #(
user_name = cl_abap_context_info=>get_user_technical_name( )
timestamp = cl_abap_context_info=>get_system_timestamp( )
client = cl_abap_context_info=>get_client( )
).

10. Formatierter Benutzername für UI

" ❌ Classic ABAP - kein direktes Äquivalent
" Oft wurde SY-UNAME direkt angezeigt: "JSMITH"
" ✅ ABAP Cloud - bessere Darstellung möglich
" Formatierter Name: "John Smith"
DATA(lv_display_name) = cl_abap_context_info=>get_user_formatted_name( ).
" Oder Benutzeralias (oft E-Mail)
DATA(lv_alias) = cl_abap_context_info=>get_user_alias( ).

11. Mehrsprachige Texte laden

" ❌ Classic ABAP
SELECT text FROM ztab_translations
WHERE text_id = @lv_text_id
AND langu = @sy-langu
INTO TABLE @DATA(lt_texts).
" ✅ ABAP Cloud
DATA(lv_langu) = cl_abap_context_info=>get_user_language_abap_format( ).
SELECT text FROM ztab_translations
WHERE text_id = @lv_text_id
AND langu = @lv_langu
INTO TABLE @DATA(lt_texts).
" ❌ Classic ABAP - System-URL manuell konfiguriert
DATA(lv_url) = |https://mycompany.sap.com/sap/bc/ui5_ui5/...|.
" ✅ ABAP Cloud - dynamische System-URL
DATA(lv_base_url) = cl_abap_context_info=>get_system_url( ).
DATA(lv_deep_link) = |{ lv_base_url }/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html#ZBooking-manage&/Booking/{ lv_booking_uuid }|.

13. Datumsberechnung mit aktuellem Datum

" ❌ Classic ABAP
DATA(lv_deadline) = sy-datum + 30.
DATA(lv_last_month) = sy-datum - 30.
" ✅ ABAP Cloud
DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
DATA(lv_deadline) = lv_today + 30.
DATA(lv_last_month) = lv_today - 30.

14. Zeitstempel für RAP Determination

" ❌ Classic ABAP in RAP Context
METHOD set_timestamps.
DATA: lv_timestamp TYPE timestamp.
GET TIME STAMP FIELD lv_timestamp.
MODIFY ENTITIES OF zi_booking IN LOCAL MODE
ENTITY Booking
UPDATE FIELDS ( created_at last_changed_at )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
created_at = lv_timestamp
last_changed_at = lv_timestamp ) ).
ENDMETHOD.
" ✅ ABAP Cloud
METHOD set_timestamps.
DATA(lv_timestamp) = cl_abap_context_info=>get_system_timestamp( ).
MODIFY ENTITIES OF zi_booking IN LOCAL MODE
ENTITY Booking
UPDATE FIELDS ( created_at last_changed_at )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
created_at = lv_timestamp
last_changed_at = lv_timestamp ) ).
ENDMETHOD.

15. Ablaufdatum-Prüfung

" ❌ Classic ABAP
IF ls_license-valid_to < sy-datum.
RAISE EXCEPTION TYPE zcx_license_expired.
ENDIF.
" ✅ ABAP Cloud
IF ls_license-valid_to < cl_abap_context_info=>get_system_date( ).
RAISE EXCEPTION TYPE zcx_license_expired.
ENDIF.

Teil 2: Wiederverwendbare Utility-Klasse

Eine zentrale Utility-Klasse vereinfacht die Migration und erhöht die Testbarkeit durch Dependency Injection.

CLASS zcl_context_helper DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_context,
user_name TYPE syuname,
user_formatted TYPE string,
user_alias TYPE string,
system_date TYPE d,
system_time TYPE t,
timestamp TYPE utclong,
time_zone TYPE timezone,
language TYPE sy-langu,
language_iso TYPE laiso,
system_id TYPE sy-sysid,
client TYPE sy-mandt,
system_url TYPE string,
END OF ty_context.
" Singleton-Pattern für einfachen Zugriff
CLASS-METHODS get_instance
RETURNING VALUE(ro_instance) TYPE REF TO zcl_context_helper.
" Alle Kontextinformationen auf einmal
METHODS get_full_context
RETURNING VALUE(rs_context) TYPE ty_context.
" Einzelne Methoden für häufige Zugriffe
METHODS get_user
RETURNING VALUE(rv_user) TYPE syuname.
METHODS get_timestamp
RETURNING VALUE(rv_timestamp) TYPE utclong.
METHODS get_date
RETURNING VALUE(rv_date) TYPE d.
METHODS get_time
RETURNING VALUE(rv_time) TYPE t.
METHODS get_language
RETURNING VALUE(rv_language) TYPE sy-langu.
METHODS get_timezone
RETURNING VALUE(rv_timezone) TYPE timezone.
" Für Unit Tests: Werte überschreiben
METHODS set_mock_user
IMPORTING iv_user TYPE syuname.
METHODS set_mock_timestamp
IMPORTING iv_timestamp TYPE utclong.
METHODS set_mock_date
IMPORTING iv_date TYPE d.
METHODS clear_mocks.
PRIVATE SECTION.
CLASS-DATA go_instance TYPE REF TO zcl_context_helper.
" Mock-Werte für Unit Tests
DATA mv_mock_user TYPE syuname.
DATA mv_mock_timestamp TYPE utclong.
DATA mv_mock_date TYPE d.
DATA mv_use_mocks TYPE abap_bool.
ENDCLASS.
CLASS zcl_context_helper IMPLEMENTATION.
METHOD get_instance.
IF go_instance IS NOT BOUND.
go_instance = NEW #( ).
ENDIF.
ro_instance = go_instance.
ENDMETHOD.
METHOD get_full_context.
rs_context = VALUE #(
user_name = get_user( )
user_formatted = cl_abap_context_info=>get_user_formatted_name( )
user_alias = cl_abap_context_info=>get_user_alias( )
system_date = get_date( )
system_time = get_time( )
timestamp = get_timestamp( )
time_zone = get_timezone( )
language = get_language( )
language_iso = cl_abap_context_info=>get_user_language_iso_format( )
system_id = cl_abap_context_info=>get_system_id( )
client = cl_abap_context_info=>get_client( )
system_url = cl_abap_context_info=>get_system_url( )
).
ENDMETHOD.
METHOD get_user.
IF mv_use_mocks = abap_true AND mv_mock_user IS NOT INITIAL.
rv_user = mv_mock_user.
ELSE.
rv_user = cl_abap_context_info=>get_user_technical_name( ).
ENDIF.
ENDMETHOD.
METHOD get_timestamp.
IF mv_use_mocks = abap_true AND mv_mock_timestamp IS NOT INITIAL.
rv_timestamp = mv_mock_timestamp.
ELSE.
rv_timestamp = cl_abap_context_info=>get_system_timestamp( ).
ENDIF.
ENDMETHOD.
METHOD get_date.
IF mv_use_mocks = abap_true AND mv_mock_date IS NOT INITIAL.
rv_date = mv_mock_date.
ELSE.
rv_date = cl_abap_context_info=>get_system_date( ).
ENDIF.
ENDMETHOD.
METHOD get_time.
rv_time = cl_abap_context_info=>get_system_time( ).
ENDMETHOD.
METHOD get_language.
rv_language = cl_abap_context_info=>get_user_language_abap_format( ).
ENDMETHOD.
METHOD get_timezone.
rv_timezone = cl_abap_context_info=>get_user_time_zone( ).
ENDMETHOD.
METHOD set_mock_user.
mv_mock_user = iv_user.
mv_use_mocks = abap_true.
ENDMETHOD.
METHOD set_mock_timestamp.
mv_mock_timestamp = iv_timestamp.
mv_use_mocks = abap_true.
ENDMETHOD.
METHOD set_mock_date.
mv_mock_date = iv_date.
mv_use_mocks = abap_true.
ENDMETHOD.
METHOD clear_mocks.
CLEAR: mv_mock_user, mv_mock_timestamp, mv_mock_date.
mv_use_mocks = abap_false.
ENDMETHOD.
METHOD if_oo_adt_classrun~main.
" Demo-Ausgabe
DATA(ls_context) = get_instance( )->get_full_context( ).
out->write( |Benutzer: { ls_context-user_name }| ).
out->write( |Datum: { ls_context-system_date }| ).
out->write( |Zeit: { ls_context-system_time }| ).
out->write( |Timestamp: { ls_context-timestamp }| ).
out->write( |Sprache: { ls_context-language }| ).
out->write( |System-ID: { ls_context-system_id }| ).
ENDMETHOD.
ENDCLASS.

Nutzung der Utility-Klasse

" Statt direktem CL_ABAP_CONTEXT_INFO-Aufruf
DATA(lo_ctx) = zcl_context_helper=>get_instance( ).
" Einzelne Werte
DATA(lv_user) = lo_ctx->get_user( ).
DATA(lv_timestamp) = lo_ctx->get_timestamp( ).
" Kompletter Kontext
DATA(ls_context) = lo_ctx->get_full_context( ).

Teil 3: Migration bestehender Reports

Schritt-für-Schritt Migration

Schritt 1: ATC-Prüfung ausführen

Rechtsklick auf Paket → Run As → ABAP Test Cockpit (ATC)
→ Check Variant: ABAP_CLOUD_READINESS
→ Alle SY-Feld-Probleme werden aufgelistet

Schritt 2: Suchen und Ersetzen in ADT

Ctrl+H → Regular Expression aktivieren
Suchen: sy-uname
Ersetzen: cl_abap_context_info=>get_user_technical_name( )
Suchen: sy-datum
Ersetzen: cl_abap_context_info=>get_system_date( )
Suchen: sy-uzeit
Ersetzen: cl_abap_context_info=>get_system_time( )

Schritt 3: Komplexere Fälle manuell prüfen

" Zeitstempel in Variable speichern (einmal holen)
DATA(lv_timestamp) = cl_abap_context_info=>get_system_timestamp( ).
" Mehrfach verwenden ohne wiederholten API-Aufruf
ls_record-created_at = lv_timestamp.
ls_record-changed_at = lv_timestamp.

Pattern: Report-Klasse modernisieren

" ❌ Classic Report mit SY-Feldern
CLASS lcl_old_report DEFINITION.
PUBLIC SECTION.
METHODS execute.
PRIVATE SECTION.
DATA: mv_run_date TYPE d,
mv_run_user TYPE syuname.
ENDCLASS.
CLASS lcl_old_report IMPLEMENTATION.
METHOD execute.
mv_run_date = sy-datum.
mv_run_user = sy-uname.
" ... Logik ...
ENDMETHOD.
ENDCLASS.
" ✅ ABAP Cloud Report
CLASS zcl_new_report DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS execute.
PRIVATE SECTION.
DATA mo_context TYPE REF TO zcl_context_helper.
METHODS initialize.
ENDCLASS.
CLASS zcl_new_report IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
initialize( ).
execute( ).
ENDMETHOD.
METHOD initialize.
mo_context = zcl_context_helper=>get_instance( ).
ENDMETHOD.
METHOD execute.
DATA(lv_run_date) = mo_context->get_date( ).
DATA(lv_run_user) = mo_context->get_user( ).
" ... Logik ...
ENDMETHOD.
ENDCLASS.

Teil 4: Häufige Fallstricke und Lösungen

Fallstrick 1: Mehrfache API-Aufrufe

" ❌ Ineffizient: API wird 3x aufgerufen
INSERT INTO ztab VALUES @( VALUE #(
created_by = cl_abap_context_info=>get_user_technical_name( )
created_at = cl_abap_context_info=>get_system_timestamp( )
changed_by = cl_abap_context_info=>get_user_technical_name( )
changed_at = cl_abap_context_info=>get_system_timestamp( )
) ).
" ✅ Effizient: Werte einmal holen
DATA(lv_user) = cl_abap_context_info=>get_user_technical_name( ).
DATA(lv_timestamp) = cl_abap_context_info=>get_system_timestamp( ).
INSERT INTO ztab VALUES @( VALUE #(
created_by = lv_user
created_at = lv_timestamp
changed_by = lv_user
changed_at = lv_timestamp
) ).

Fallstrick 2: Zeitzone bei Datumsvergleichen

" ❌ Problem: Systemzeit vs. lokale Zeit
DATA(lv_system_date) = cl_abap_context_info=>get_system_date( ).
" In verschiedenen Zeitzonen kann das falsche Datum sein!
" ✅ Lösung: Explizite Zeitzone berücksichtigen
DATA: lv_local_date TYPE d,
lv_local_time TYPE t.
CONVERT TIME STAMP cl_abap_context_info=>get_system_timestamp( )
TIME ZONE cl_abap_context_info=>get_user_time_zone( )
INTO DATE lv_local_date TIME lv_local_time.
" Jetzt ist lv_local_date das Datum aus Sicht des Benutzers

Fallstrick 3: SY-SUBRC nach API-Aufruf

" ❌ Falsche Annahme: SY-SUBRC wird durch API gesetzt
DATA(lv_user) = cl_abap_context_info=>get_user_technical_name( ).
IF sy-subrc <> 0.
" Wird nie ausgeführt - API setzt kein SY-SUBRC!
ENDIF.
" ✅ Richtig: API hat keinen Fehlerfall
" CL_ABAP_CONTEXT_INFO gibt immer einen Wert zurück
DATA(lv_user) = cl_abap_context_info=>get_user_technical_name( ).
" Kein Check nötig

Fallstrick 4: Batch-Modus (SY-BATCH)

" ❌ Classic ABAP: Batch-Modus prüfen
IF sy-batch = abap_true.
" Hintergrundverarbeitung
ENDIF.
" ✅ ABAP Cloud: Kein SY-BATCH
" In ABAP Cloud gibt es keine klassischen Reports
" Application Jobs haben eigene Mechanismen
" Falls nötig: Über eigene Parameter steuern
CLASS zcl_my_job DEFINITION.
PUBLIC SECTION.
METHODS execute
IMPORTING iv_is_background TYPE abap_bool DEFAULT abap_false.
ENDCLASS.

Fallstrick 5: Hardcodierte Systemprüfung

" ❌ Problematisch: Hardcodierte System-IDs
IF cl_abap_context_info=>get_system_id( ) = 'PRD'.
" Produktions-spezifischer Code
ENDIF.
" ✅ Besser: Konfigurationsbasiert über Customizing
" In ABAP Cloud: Communication Scenario oder Table verwenden
SELECT SINGLE is_production FROM ztab_config
WHERE system_id = @( cl_abap_context_info=>get_system_id( ) )
INTO @DATA(lv_is_production).

Unit Tests mit Mock-Werten

Die Utility-Klasse ermöglicht einfaches Testen:

CLASS ltc_booking_test DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zcl_booking_handler.
DATA mo_context TYPE REF TO zcl_context_helper.
METHODS setup.
METHODS teardown.
METHODS test_booking_with_mocked_date FOR TESTING.
ENDCLASS.
CLASS ltc_booking_test IMPLEMENTATION.
METHOD setup.
mo_context = zcl_context_helper=>get_instance( ).
mo_cut = NEW #( ).
" Mock-Werte setzen
mo_context->set_mock_date( '20260301' ).
mo_context->set_mock_user( 'TESTUSER' ).
mo_context->set_mock_timestamp( CONV utclong( '2026-03-01 10:00:00' ) ).
ENDMETHOD.
METHOD teardown.
mo_context->clear_mocks( ).
ENDMETHOD.
METHOD test_booking_with_mocked_date.
" Given: Buchung für morgen
DATA(ls_booking) = VALUE zif_booking=>ty_booking(
flight_date = '20260302'
).
" When: Validierung ausführen
DATA(lv_is_valid) = mo_cut->validate_booking( ls_booking ).
" Then: Buchung ist gültig (Datum liegt in der Zukunft)
cl_abap_unit_assert=>assert_true( lv_is_valid ).
ENDMETHOD.
ENDCLASS.

Checkliste für die Migration

## SY-Feld Migration Checkliste
### Vorbereitung
- [ ] ATC mit ABAP_CLOUD_READINESS ausführen
- [ ] Utility-Klasse ZCL_CONTEXT_HELPER anlegen
- [ ] Alle betroffenen Objekte identifizieren
### Migration pro Objekt
- [ ] SY-UNAME → get_user_technical_name( )
- [ ] SY-DATUM → get_system_date( )
- [ ] SY-UZEIT → get_system_time( )
- [ ] SY-LANGU → get_user_language_abap_format( )
- [ ] SY-ZONLO → get_user_time_zone( )
- [ ] SY-MANDT → get_client( )
- [ ] SY-SYSID → get_system_id( )
- [ ] GET TIME STAMP → get_system_timestamp( )
### Qualitätssicherung
- [ ] Unit Tests angepasst (Mocking)
- [ ] ATC erneut ausführen
- [ ] Manuelle Tests durchführen

Fazit

Die Migration von SY-Feldern folgt klaren Mustern:

  1. Direkte Ersetzung für die meisten Fälle mit CL_ABAP_CONTEXT_INFO
  2. Utility-Klasse für zentrale Verwaltung und Testbarkeit
  3. Werte cachen bei mehrfacher Verwendung
  4. Zeitzonen beachten bei Datumsvergleichen

Die Umstellung ist technisch einfach, erfordert aber systematisches Vorgehen. Der ATC hilft dabei, alle Stellen zu finden.

Für eine vollständige Übersicht aller SY-Felder siehe System-Felder in ABAP Cloud. Mehr zur Clean Core Strategie findest du unter Clean Core Level-Konzept und zur praktischen Umsetzung in der Implementierungs-Checkliste.