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-readyDATA(lv_user) = sy-uname.ls_document-created_by = sy-uname.WHERE created_by = @sy-uname
" ✅ ABAP Cloud - direkte MigrationDATA(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 ABAPDATA(lv_today) = sy-datum.IF ls_booking-flight_date < sy-datum. " AbgelaufenENDIF.
" ✅ ABAP CloudDATA(lv_today) = cl_abap_context_info=>get_system_date( ).IF ls_booking-flight_date < cl_abap_context_info=>get_system_date( ). " AbgelaufenENDIF.3. Systemzeit (SY-UZEIT)
" ❌ Classic ABAPDATA(lv_time) = sy-uzeit.ls_log-logged_at_time = sy-uzeit.
" ✅ ABAP CloudDATA(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 ABAPDATA: lv_timestamp TYPE timestamp.GET TIME STAMP FIELD lv_timestamp.
" ✅ ABAP Cloud - besser lesbar und typsicherDATA(lv_timestamp) = cl_abap_context_info=>get_system_timestamp( ).
" Hinweis: Rückgabetyp ist UTCLONG (empfohlen für Datenbank)5. Anmeldesprache (SY-LANGU)
" ❌ Classic ABAPSELECT SINGLE text FROM ztab_texts WHERE langu = @sy-langu INTO @DATA(lv_text).
" ✅ ABAP CloudSELECT 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 ABAPDATA(lv_timezone) = sy-zonlo.CONVERT TIME STAMP lv_utc TIME ZONE sy-zonlo INTO DATE lv_local_date TIME lv_local_time.
" ✅ ABAP CloudDATA(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 ABAPDATA(lv_client) = sy-mandt.lv_table_key = |{ sy-mandt }{ lv_id }|.
" ✅ ABAP CloudDATA(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 ABAPIF sy-sysid = 'PRD'. " ProduktionssystemENDIF.
" ✅ ABAP CloudIF cl_abap_context_info=>get_system_id( ) = 'PRD'. " ProduktionssystemENDIF.9. Audit-Logging mit Benutzer und Zeitstempel
" ❌ Classic ABAPls_audit_log = VALUE #( user_name = sy-uname log_date = sy-datum log_time = sy-uzeit client = sy-mandt).
" ✅ ABAP Cloud - komplett migriertls_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 ABAPSELECT text FROM ztab_translations WHERE text_id = @lv_text_id AND langu = @sy-langu INTO TABLE @DATA(lt_texts).
" ✅ ABAP CloudDATA(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).12. E-Mail-Link mit System-URL
" ❌ Classic ABAP - System-URL manuell konfiguriertDATA(lv_url) = |https://mycompany.sap.com/sap/bc/ui5_ui5/...|.
" ✅ ABAP Cloud - dynamische System-URLDATA(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 ABAPDATA(lv_deadline) = sy-datum + 30.DATA(lv_last_month) = sy-datum - 30.
" ✅ ABAP CloudDATA(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 ContextMETHOD 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 CloudMETHOD 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 ABAPIF ls_license-valid_to < sy-datum. RAISE EXCEPTION TYPE zcx_license_expired.ENDIF.
" ✅ ABAP CloudIF 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-AufrufDATA(lo_ctx) = zcl_context_helper=>get_instance( ).
" Einzelne WerteDATA(lv_user) = lo_ctx->get_user( ).DATA(lv_timestamp) = lo_ctx->get_timestamp( ).
" Kompletter KontextDATA(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 aufgelistetSchritt 2: Suchen und Ersetzen in ADT
Ctrl+H → Regular Expression aktivieren
Suchen: sy-unameErsetzen: cl_abap_context_info=>get_user_technical_name( )
Suchen: sy-datumErsetzen: cl_abap_context_info=>get_system_date( )
Suchen: sy-uzeitErsetzen: 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-Aufrufls_record-created_at = lv_timestamp.ls_record-changed_at = lv_timestamp.Pattern: Report-Klasse modernisieren
" ❌ Classic Report mit SY-FeldernCLASS 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 ReportCLASS 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 aufgerufenINSERT 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 holenDATA(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 ZeitDATA(lv_system_date) = cl_abap_context_info=>get_system_date( )." In verschiedenen Zeitzonen kann das falsche Datum sein!
" ✅ Lösung: Explizite Zeitzone berücksichtigenDATA: 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 BenutzersFallstrick 3: SY-SUBRC nach API-Aufruf
" ❌ Falsche Annahme: SY-SUBRC wird durch API gesetztDATA(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ückDATA(lv_user) = cl_abap_context_info=>get_user_technical_name( )." Kein Check nötigFallstrick 4: Batch-Modus (SY-BATCH)
" ❌ Classic ABAP: Batch-Modus prüfenIF sy-batch = abap_true. " HintergrundverarbeitungENDIF.
" ✅ ABAP Cloud: Kein SY-BATCH" In ABAP Cloud gibt es keine klassischen Reports" Application Jobs haben eigene Mechanismen
" Falls nötig: Über eigene Parameter steuernCLASS 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-IDsIF cl_abap_context_info=>get_system_id( ) = 'PRD'. " Produktions-spezifischer CodeENDIF.
" ✅ Besser: Konfigurationsbasiert über Customizing" In ABAP Cloud: Communication Scenario oder Table verwendenSELECT 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ührenFazit
Die Migration von SY-Feldern folgt klaren Mustern:
- Direkte Ersetzung für die meisten Fälle mit
CL_ABAP_CONTEXT_INFO - Utility-Klasse für zentrale Verwaltung und Testbarkeit
- Werte cachen bei mehrfacher Verwendung
- 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.