This is a test message to test the length of the message box.
Login
|
ABAP Datum und Uhrzeit
Erstellt von Software-Heroes

ABAP - Datum und Uhrzeit

427

Schauen wir uns in diesem Artikel einmal die Datentypen für das Datum und die Uhrzeit in ABAP etwas genauer an. Hat sich zwischen den verschiedenen Releases etwas geändert und was solltest du heute noch nutzen?

Werbung


In diesem Artikel schauen wir uns verschiedene Grunddatentypen an und validieren verschiedene Szenarien, um am Ende das Resultat zu prüfen und eine Empfehlung auszusprechen.

 

Einleitung

In den Anfangszeiten von ABAP und der Integration von Datenbanken, sind viele Dinge und Mechanismen entstanden, die wir in der Entwicklung noch jeden Tag verwenden. Entsprechend sind teilweise technische Schulden entstanden, die für den erfahrenen ABAP Entwickler klar sind, vielleicht aber für Kopfschütteln bei den jungen Entwicklern sorgen. Daher wollen wir uns in diesem Artikel einmal die Grunddatentypen für das Datum und die Uhrzeit anschauen.

 

Vorbereitung

Zur Vorbereitung des Testfalls definieren wir eine Tabelle im System, die uns die verschiedenen Typen zur Verfügung stellen soll. Über die eingebauten Datentypen unter ABAP, können wir uns die spezifischen Datentypen in der Tabelle definieren. Später können wir dann die Tabelle zur Typisierung und zur Validierung verwenden.

@EndUserText.label : 'Date Time Examples'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_dmo_datim {
  key client     : abap.clnt not null;
  key identifier : abap.char(20) not null;
  classic_date   : abap.dats;
  hana_date      : abap.datn;
  classic_time   : abap.tims;
  hana_time      : abap.timn;
}

 

Typen

Um welche Typen geht es nun eigentlich in diesem Beispiel? Wir wollen uns dazu einmal die klassischen Typen für Datum (DATS) und Uhrzeit (TIMS) anschauen und mit den neuen Typen DATN und TIMN vergleichen. In diesem Kapitel schauen wir uns erst einmal die Typen im Grundaufbau an.

 

Klassisch

Die klassischen Datentypen werden als Charakter auf der Datenbank abgelegt und im jeweils korrekten Format vom System erwartet. Beim Einfügen der Daten erfolgt erst einmal keine Validierung der Daten, was im schlimmsten Fall zu Fehlern in der Folgeverarbeitung führen kann.

 

HANA

Die Typen wurden mit der HANA Datenbank eingeführt und stellen nun einen nativen Typen für Datum und Uhrzeit auf der Datenbank dar. Bedeutet aber auch, dass immer eine Validierung der Daten stattfindet, bevor sie auf die Datenbank geschrieben werden können. Damit hast du etwas mehr Sicherheit bei der Arbeit mit den Typen.

 

Compiler

Schauen wir uns in diesem Kapitel einmal die Arbeit mit dem Compiler an, wo erhalten wir eigentlich vom System bereits Hinweise, dass etwas nicht stimmt. Dazu definieren wir drei verschiedene Arten von Beispielen:

  • Leer - In diesem Beispiel übergeben wir leere Char Literale an die Variablen.
  • Korrekt - Wir übergeben jeweils richtige Daten an die verschiedenen Felder und würden hier auch keine weiteren Fehler erwarten.
  • Falsch - In diesem Beispiel sind die Daten nicht korrekt und passen nicht wirklich zum Format.

 

Übergeben wir zum Beispiel fehlerhafte Werte an die Felder. Hier existiert der 13te Monat nicht und der Tag hat leider nur 24 Stunden.

db_type-classic_date = '20201331'.
db_type-hana_date    = '20201331'.
db_type-classic_time = '254539'.
db_type-hana_time    = '254539'.

 

Damit erhalten wir bei allen Übergaben eine entsprechende Warnung vom System, dass die Werte nicht korrekt sind. Bei den leeren Datentypen wird uns der kleinste Wert vorgeschlagen und bei den falschen Daten die nächsten richtigen Daten. Damit funktionieren alle Datentypen eigentlich gleich und bei hartcodierten Werten erhalten wir bereits vom Compiler einen Hinweis.

 

Funktionen

Wie sieht es eigentlich mit SQL-Funktionen aus? SAP hat in diesem Bereich verschiedene Funktionen ausgeliefert, um die Inhalte von solchen Feldern zu validieren und zu konvertieren. Diese Funktionen werden aber vor allem für ABAP SQL ausgeliefert, sind damit aber auch in einem SELECT funktionsfähig. Legen wir uns dazu eine lokale Tabelle mit verschiedenen Use-Cases an.

DATA locals TYPE STANDARD TABLE OF zbs_dmo_datim.

locals = VALUE #( ( identifier   = 'EMPTY' )
                  ( identifier   = 'INITIAL'
                    classic_date = '00000000'
                    hana_date    = '00000000'
                    classic_time = '000000'
                    hana_time    = '000000' )
                  ( identifier   = 'OK'
                    classic_date = '20201231'
                    hana_date    = '20201231'
                    classic_time = '154539'
                    hana_time    = '154539' )
                  ( identifier = 'HANA_NOK'
                    hana_date  = '20201331'
                    hana_time  = '254539' )
                  ( identifier   = 'CLASSIC_NOK'
                    classic_date = '20201331'
                    classic_time = '254539' )
                  ( identifier   = 'WRONG'
                    classic_date = 'ABC'
                    hana_date    = 'DEF'
                    classic_time = 'GHI'
                    hana_time    = 'JKL' ) ).

 

Nun können wir einen SELECT auf die interne Tabelle durchführen und dabei verwenden wir die Funktion DATS_IS_VALID und TIMS_IS_VALID um die verschiedenen Spalten zu validieren.

SELECT FROM @locals AS validation
  FIELDS identifier,
         dats_is_valid( classic_date ) AS dats_valid,
         dats_is_valid( hana_date )    AS datn_valid,
         tims_is_valid( classic_time ) AS tims_valid,
         tims_is_valid( hana_time )    AS timn_valid
  INTO TABLE @DATA(validated_content).

 

Dabei erzeugen wir eine neue Tabelle mit dem Schlüssel (IDENTIFIER) und für jede validierte Spalte ein neues Feld. Wie sieht also die neue Tabelle im Debugger aus?

 

Aus diesen Beobachtungen können wir einige Fakten ableiten:

  • Für die neuen Datentypen funktionieren die beiden Funktionen nicht, sie liefern immer ein OK zurück und sind damit nicht zu gebrauchen.
  • Für die neuen Datentypen gibt es keine Funktion zur Validierung auf dieser Ebene, allerdings können wir mit DATS_FROM_DATN eine Konvertierung durchführen. Ein Nachteil ist allerdings, dass die Funktion einen korrekten Typen benötigt. Übergeben wir falsche Daten, dann müssen wir die Ausnahme CX_SY_OPEN_SQL_DB abfangen, was für unsere Tabelle leider kein Ergebnis erzeugt.
  • Die klassischen Datentypen können wir auf einfache Art und Weise über den SELECT und die ABAP SQL Funktion validieren.
  • Ein initiales Datum ist ebenfalls falsch, hier muss laut Dokumentation mindestens der Wert "00010101" gesetzt sein, damit ein valides Datum erkannt wird. Hier musst du zusätzlich eine IS INITIAL Prüfung verwenden, um den Fall abzudecken.

 

Datenbank

Im nächsten Schritt schauen wir einmal auf die Datenbank und was eigentlich passiert, wenn wir trotz sorgfältiger Prüfung, falsche Daten versuchen zu speichern. In unserem Szenario versuchen wir mehrere Dinge mit den unterschiedlichen Arten:

  • Initial - Einfügen von leeren Werten in die Datenbank.
  • Inkorrekt - Die Daten sind korrekt aufgebaut, aber außerhalb der gültigen und zulässigen Werte. Zum Beispiel ist der 32.12.2020 ein falsches Datum.
  • Fehlerhaft - Im dritten Fall übergeben wir komplett falsche Daten, wie zum Beispiel Buchstaben für eine Uhrzeit.

 

Klassisch

Da der klassische Datentyp nur ein Charakter ist und keine Validierung auf der Datenbank erfolgt, wird hier das Einfügen in jedem Szenario funktionieren. Nehmen wir im ersten Beispiel einmal nicht existente Werte.

db_type-identifier   = 'INCO_CLASSIC'.
db_type-classic_date = '20201331'.
db_type-classic_time = '254539'.

INSERT zbs_dmo_datim FROM @db_type.

out->write( sy-subrc ).
out->write( sy-dbcnt ).

 

Im zweiten Beispiel versuchen wir Datenmüll in die Datenbank zu übernehmen.

db_type-identifier   = 'WROG_CLASSIC'.
db_type-classic_date = 'ABC'.
db_type-classic_time = 'DEF'.

 

HANA

Versuchen wir die gleichen Beispiele im Bereich der nativen Typen, erwarten wir einen Abbruch oder eine Fehlermeldung. In diesem Fall wird die Ausnahme CX_SY_OPEN_SQL_DB erzeugt und wenn wir sie nicht abfangen, bricht unsere Verarbeitung mit einem Dump ab.

db_type-identifier = 'INCO_HANA'.
db_type-hana_date  = '20201331'.
db_type-hana_time  = '254539'.

TRY.
    INSERT zbs_dmo_datim FROM @db_type.

    out->write( sy-subrc ).
    out->write( sy-dbcnt ).

  CATCH cx_root INTO DATA(error).
    out->write( error->get_text( ) ).
ENDTRY.

 

Ergebnis

Schauen wir einmal auf das Ergebnis in der Datenbank. Grundsätzlich funktioniert der initiale Wert für alle Datentypen. Allerdings werden die fehlerhaften Werte für den klassischen Datentyp alle in die Datenbank übernommen und können nun zu weiteren Problemen führen. Für die neuen Typen findest du keinen fehlerhaften Wert auf der Datenbank.

 

Vollständiges Beispiel

Hier findest du das vollständige Beispiel der Implementierung der Klasse und kannst es damit bei dir im System nachstellen. Die benötigte Tabelle findest du oben im Schritt "Vorbereitung".

CLASS zcl_bs_demo_date_time DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    DATA db_type TYPE zbs_dmo_datim.

    METHODS empty_types
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS correct_values
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS incorrect_values
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS insert_initial
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS insert_incorrect_classic
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS insert_incorrect_hana
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS insert_wrong_classic
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS insert_wrong_hana
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS validate_types
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

ENDCLASS.


CLASS zcl_bs_demo_date_time IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DELETE FROM zbs_dmo_datim.
    COMMIT WORK.

    empty_types( out ).
    correct_values( out ).
    incorrect_values( out ).
    insert_initial( out ).
    insert_incorrect_classic( out ).
    insert_incorrect_hana( out ).
    insert_wrong_classic( out ).
    insert_wrong_hana( out ).
    validate_types( out ).

    COMMIT WORK.
  ENDMETHOD.


  METHOD empty_types.
    CLEAR db_type.

    db_type-classic_date = ''.
    db_type-hana_date    = ''.
    db_type-classic_time = ''.
    db_type-hana_time    = ''.

    out->write( db_type ).
  ENDMETHOD.


  METHOD correct_values.
    CLEAR db_type.

    db_type-classic_date = '20201231'.
    db_type-hana_date    = '20201231'.
    db_type-classic_time = '154539'.
    db_type-hana_time    = '154539'.

    out->write( db_type ).
  ENDMETHOD.


  METHOD incorrect_values.
    CLEAR db_type.

    db_type-classic_date = '20201331'.
    db_type-hana_date    = '20201331'.
    db_type-classic_time = '254539'.
    db_type-hana_time    = '254539'.

    out->write( db_type ).
  ENDMETHOD.


  METHOD insert_initial.
    CLEAR db_type.

    db_type-identifier = 'INTIAL'.

    TRY.
        INSERT zbs_dmo_datim FROM @db_type.

        out->write( sy-subrc ).
        out->write( sy-dbcnt ).

      CATCH cx_root INTO DATA(error).
        out->write( error->get_text( ) ).
    ENDTRY.
  ENDMETHOD.


  METHOD insert_incorrect_classic.
    CLEAR db_type.

    db_type-identifier   = 'INCO_CLASSIC'.
    db_type-classic_date = '20201331'.
    db_type-classic_time = '254539'.

    TRY.
        INSERT zbs_dmo_datim FROM @db_type.

        out->write( sy-subrc ).
        out->write( sy-dbcnt ).

      CATCH cx_root INTO DATA(error).
        out->write( error->get_text( ) ).
    ENDTRY.
  ENDMETHOD.


  METHOD insert_incorrect_hana.
    CLEAR db_type.

    db_type-identifier = 'INCO_HANA'.
    db_type-hana_date  = '20201331'.
    db_type-hana_time  = '254539'.

    TRY.
        INSERT zbs_dmo_datim FROM @db_type.

        out->write( sy-subrc ).
        out->write( sy-dbcnt ).

      CATCH cx_root INTO DATA(error).
        out->write( error->get_text( ) ).
    ENDTRY.
  ENDMETHOD.


  METHOD insert_wrong_classic.
    CLEAR db_type.

    db_type-identifier   = 'WROG_CLASSIC'.
    db_type-classic_date = 'ABC'.
    db_type-classic_time = 'DEF'.

    TRY.
        INSERT zbs_dmo_datim FROM @db_type.

        out->write( sy-subrc ).
        out->write( sy-dbcnt ).

      CATCH cx_root INTO DATA(error).
        out->write( error->get_text( ) ).
    ENDTRY.
  ENDMETHOD.


  METHOD insert_wrong_hana.
    CLEAR db_type.

    db_type-identifier = 'WROG_HANA'.
    db_type-hana_date  = 'ABC'.
    db_type-hana_time  = 'DEF'.

    TRY.
        INSERT zbs_dmo_datim FROM @db_type.

        out->write( sy-subrc ).
        out->write( sy-dbcnt ).

      CATCH cx_root INTO DATA(error).
        out->write( error->get_text( ) ).
    ENDTRY.
  ENDMETHOD.


  METHOD validate_types.
    DATA locals TYPE STANDARD TABLE OF zbs_dmo_datim.

    locals = VALUE #( ( identifier   = 'EMPTY' )
                      ( identifier   = 'INITIAL'
                        classic_date = '00000000'
                        hana_date    = '00000000'
                        classic_time = '000000'
                        hana_time    = '000000' )
                      ( identifier   = 'OK'
                        classic_date = '20201231'
                        hana_date    = '20201231'
                        classic_time = '154539'
                        hana_time    = '154539' )
                      ( identifier = 'HANA_NOK'
                        hana_date  = '20201331'
                        hana_time  = '254539' )
                      ( identifier   = 'CLASSIC_NOK'
                        classic_date = '20201331'
                        classic_time = '254539' )
                      ( identifier   = 'WRONG'
                        classic_date = 'ABC'
                        hana_date    = 'DEF'
                        classic_time = 'GHI'
                        hana_time    = 'JKL' ) ).

    SELECT FROM @locals AS validation
      FIELDS identifier,
             dats_is_valid( classic_date ) AS dats_valid,
             dats_is_valid( hana_date )    AS datn_valid,
*             dats_is_valid( dats_from_datn( hana_date ) ) AS datn_valid_converted,
             tims_is_valid( classic_time ) AS tims_valid,
             tims_is_valid( hana_time )    AS timn_valid
*             tims_is_valid( tims_from_timn( hana_time ) ) AS timn_valid_converted
      INTO TABLE @DATA(validated_content).

    out->write( validated_content ).
  ENDMETHOD.
ENDCLASS.

 

Fazit

Die Typen verhalten sich in den meisten Fällen erst einmal gleich und das hindert uns nicht während der Verarbeitung falsche Werte und Einträge zu erzeugen. Allerdings bekommst du spätestens beim Speichern den Hinweis, dass etwas nicht so sauber ist oder sogar einen Abbruch, wenn du das Fehlerhandling vergessen hast. Du solltest auf jeden Fall den neuen Datentypen verwenden, da er dir mehr Sicherheit im System und mit den Daten gibt.

 

Quellen:
SAP Help - Handling of Dates and Times


Enthaltene Themen:
Modernes ABAPDatumUhrzeitDatentyp
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Dienstag und Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP - XCO Logging

Kategorie - ABAP

Die XCO Klassen sind Bestandteil der ABAP Cloud APIs und verfügen über zahlreiche Funktionen, die nicht immer so einfach zu verstehen sind. In diesem Artikel schauen wir uns das Logging Objekt im Detail an.

16.12.2025

ABAP - Der richtige Schlüssel

Kategorie - ABAP

Wie sieht es eigentlich bei der Nutzung von internen Tabellen aus? Immer noch TYPE TABLE in ABAP und die Tabelle ist fertig definiert?

14.11.2025

ABAP - XCO Reguläre Ausdrücke

Kategorie - ABAP

Schauen wir uns einmal die XCO Klassen für die regulären Ausdrücke an und wie damit recht einfach REGEX gegen Texte und Eingaben in ABAP Cloud absetzen kannst. Dabei vergleichen wir auch mit klassischem ABAP.

07.11.2025

ABAP - Escape

Kategorie - ABAP

Schauen wir uns in diesem Artikel einmal im Detail verschiedene Escape Varianten an, die du für die ABAP Entwicklung und Sicherheit im System benötigst.

07.10.2025

ABAP - Assign

Kategorie - ABAP

In diesem Artikel schauen wir uns verschiedene Varianten von ASSIGN an und wie du sie in ABAP im Alltag nutzen kannst, um deine Entwicklung effektiver zu machen.

26.09.2025