
ABAP Cloud - Datumsfunktionen
Du bist auf der Suche nach der Funktion für das Quartal eines Datums, den letzten Tag im Monat oder den ersten Tag der Woche? Mit ABAP Cloud brauchst du dafür keine Funktionsbausteine mehr. Schauen wir uns die Beispiele an.
Inhaltsverzeichnis
In diesem Artikel schauen wir uns den neuen Core Data Service für die Datumsfunktionen an und wieso du eigentlich keine Funktionsbausteine mehr benötigst.
Einleitung
Datumsfunktionen sind ein wichtiger Bestandteil in der Entwicklung von Software, vor allem im Bereich der Finanzen oder wo verschiedene Daten berechnet werden müssen. In der Vergangenheit gab es hier vor allem Funktionsbausteine, die verwendet wurden, um den letzten Tag eines Monats zu ermitteln oder zum Beispiel zu prüfen, in welchem Quartal man sich aktuell befindet. Ebenso nötig waren Funktionen, um festzustellen, ob ein Datum zum Beispiel an einem Montag liegt oder ob es sich an einem Wochenende befindet. Mit ABAP Cloud wurden die Funktionsbausteine obsolet, aktuell gibt es aber auch keine freigegebene Klasse, mit der diese verschiedenen Funktionen ausgeführt und aufgerufen werden können.
Core Data Service
Hier stellt SAP mittlerweile einen Core Data Service zur Verfügung, der einige dieser Funktionen enthält. Dabei handelt es sich um den View "I_CalendarDate", den wir im System finden und ausführen können und der uns für verschiedene Daten die entsprechend berechneten Werte zurückgibt. Dabei werden die verschiedenen Daten auch nicht zur Laufzeit berechnet, sondern aus der Datenbank gelesen. Das heißt, alle Werte wurden bereits vorberechnet und persistiert. Hierbei stehen die Werte vom 01.01.1900 bis zum 31.12.9999 zur Verfügung, sodass eigentlich die gängigsten Bereiche abgedeckt sein sollten.
Schauen wir uns das dann im Preview an, sehen wir die verschiedenen Felder. Dabei ist der Tag oder der Kalendertag das eigentliche Schlüsselfeld und wir erhalten aufgeschlüsselt die verschiedenen Informationen wie das eigentliche Jahr, das Quartal, den Monat, die Woche und weitere zusammengesetzte Informationen, die vom Datum abhängig sind. Damit können wir mit einem SELECT auf den Core Data Service dann verschiedene Datumsinformationen ableiten.
Es gibt auch durchaus Informationen, die etwas komplexer sind, wie zum Beispiel den ersten Tag einer Woche, den Wochentag oder den Kalendertag innerhalb des Jahres. Hierfür gibt es praktische Spalten, die du lesen kannst, wenn du sie benötigst. Informationen wie das Jahr oder den Monat kannst du grundsätzlich auch aus dem Datum mit Substring-Funktionen ableiten.
Wochentage
Hier fallen aber auch die ersten kleinen Unterschiede auf, wenn wir einmal ins Detail gehen. So wird zum Beispiel der Wochentag im ABAP-Standard von 1 bis 6 durchgezählt und der Sonntag ist jeweils die 0, wie im typischen amerikanischen Kalender. Dies wird repräsentiert im Systemfeld SY-FDAYW. Dazu im Gegenteil steht der Core Data Service, denn hier wird der Tag durchgezählt von 1 bis 7, das heißt, der Sonntag ist die 7 und der Montag ist dann jeweils die 1. Damit lassen sich die beiden Werte nicht direkt miteinander vergleichen, sondern hier muss ein Mapping des Sonntag erfolgen, je nachdem auf welches Feld wir referenzieren.
Open Source
Dazu haben wir entsprechend unser Projekt für die Systemfelder erweitert, um neben den eigentlichen Systemfeldern auch noch verschiedene Datumsfunktionen als Standard zur Verfügung zu stellen. Hier auch die Verknüpfung zu den Wochentagen, da dies bereits eine Methode war. Welche wir nun durch den neuen Standard austauschen können.
Architektur
Wie immer möchten wir unsere Klassenarchitektur testbar aufbauen und erstellen jeweils eine Factory und einen Injector, um später die Logik testbar zu gestalten. Alle Funktionen handhaben wir in einer Instanz, um die Wiederverwendbarkeit sicherzustellen und implementieren dazu ein Interface.
Methoden
Dazu stellen wir ein entsprechendes Interface zur Verfügung und geben einige Strukturen und Methoden an die Hand, die wir später verwenden möchten. Hier handelt es sich vor allem um die komplexen Berechnungsmethoden, die nicht allzu einfach aus dem Datum ableitbar sind oder wofür wir auch XCO-Klassen haben. So zum Beispiel für den ersten und letzten Tag des Monats. Genauso für die Woche: Hier hat der Standard keine Methode zur Verfügung gestellt, und wir rechnen uns selbst den letzten Tag der Woche aus. Das Quartal, die Woche und der Wochentag sind ebenso Bestandteil der Funktionen, die wir nach außen geben. Zusätzlich haben wir noch eine Methode GET_RAW_DATE, um den kompletten Datensatz zurückzugeben, falls dieser benötigt wird.
Performance
Die Performance haben wir dabei versucht zu optimieren, indem wir den Datensatz nach dem Lesen direkt in der Klasse puffern und somit verschiedene Aktionen mit dem gleichen Datum ausführen können, ohne noch einmal nachlesen zu müssen. Zusätzlich lässt sich pro Klasseninstanz ein Datum persistieren, das heißt, eine Instanz stellt genau ein Datum dar, auf dem wir verschiedene Operationen ausführen können. Die Erstellung erfolgt über die Factory oder zum aktuellen Tag über die Systemfelder.
Verwendung
Wollen wir das Objekt verwenden, können wir uns aktuell zwei verschiedene Varianten aussuchen: Im ersten Schritt können wir über die Systemfelder gehen und uns die Date Functions zurückgeben lassen. Darüber können wir dann zum Beispiel den Wochentag ableiten. In einer anderen Version können wir auch das Ganze verketten, über das Systemobjekt die Date Functions holen, darüber den Wochentag ableiten und diesem ein Feld zuweisen.
" Via object
DATA(today) = sy->date_functions( ).
DATA(weekday) = today->get_weekday( ).
" Chained
DATA(weekday_new) = sy->date_functions( )->get_weekday( ).
Als zweite Variante steht uns natürlich die Factory zur Verfügung. Über die Factory können wir eine neue Instanz anlegen für ein entsprechendes Datum, in diesem Fall nehmen wir das Systemdatum minus 1, also den gestrigen Tag. Über dieses Objekt können wir dann ebenfalls eine Methode ausführen. So können wir einmal über die Systemfelder arbeiten, aber auch das Objekt direkt verwenden, wenn wir zum Beispiel ein anderes Datum als Referenz benötigen.
DATA(yesterday) = zcl_date_factory=>create_date( CONV #( sy->system_date( ) - 1 ) ).
DATA(last_day_of_week) = yesterday->get_last_day_of_week( ).
Testing
Um die Tests für das Open-Source-Projekt zu erstellen, haben wir in diesem Fall keine manuellen Tests durchgeführt, sondern einen ABAP Agent über den Code laufen lassen. Dabei haben wir Agentic AI über VS Code verwendet, um uns Unit-Tests für unsere Klasse generieren zu lassen. Grundsätzlich haben wir nach der Generierung einmal die Ergebnisse geprüft. Entsprechend auffällig ist, dass wir pro Testmethode mehrere Testfälle abbilden, was nicht der Best Practice für ABAP Unit entspricht. Hier könnten wir grundsätzlich dem Agenten noch sagen, dass er die Methoden aussplitten soll, was aber entsprechend langen Testcode erzeugen würde.
Das Beispiel für die Datumsfunktionen lässt sich aber sehr gut verwenden, um darüber automatisierte Unit-Tests generieren zu lassen. Insgesamt hat der Agent für verschiedene Use Cases und Edge Cases Daten erzeugt. Ebenfalls hat er zum Beispiel für die Kalenderwoche verschiedene Berechnungsmethoden angewandt, die nach den ISO-Standards definiert sind, um die richtige Kalenderwoche zu ermitteln. Die Kommentare und Nachrichten sind ebenso hilfreich, um die Testfälle einfacher zu verstehen.
Fazit
Verschiedene Datumsfunktionen befinden sich nun nicht mehr in Funktionsbausteinen, um die Ermittlung durchzuführen, sondern können direkt aus einem Core Data Service gelesen werden. Alternativ kannst du für eine bessere Handhabung auch eigene Logiken anlegen, um aus dem Core Data Service zu verwenden und zu lesen. Die Information zum Core Data Service kann dir helfen, ohne viel Aufwand und Berechnung das richtige Datum zu erhalten.
Weitere Informationen:
GitHub - System Fields



