[ABAP] Native SQL-Zugriff auf eine Oracle-Datenbank

* DBCO: Transaktion zur Pflege der Datenbankverbindung zur Oracle-DB
* DBACOCKPIT
* DBCON: Tabelle der Datenbankverbindungen

* http://www.saptechnical.com/Tutorials/Basis/Oracle/RetrieveData.htm
* http://sqlines.com/oracle-to-sql-server/to_char_datetime
* https://archive.sap.com/discussions/thread/33542
* https://archive.sap.com/discussions/thread/107384
* https://blogs.sap.com/2012/12/28/native-sql-its-use-with-database-connection-in-sap/
* https://help.sap.com/http.svc/rc/abapdocu_750_index_htm/7.50/de-DE/abapexec_connection.htm

* Beispieldatentyp für verschiedene Oracle-Datentypen
TYPES: BEGIN OF ty_s_tableline,
         col_number     TYPE i,                      " NUMBER
         col_number10_2 TYPE p LENGTH 10 DECIMALS 2, " NUMBER (10,2)
         col_number5    TYPE p LENGTH 5 DECIMALS 0,  " NUMBER (5)
         col_char       TYPE c LENGTH 16,            " VARCHAR2 (16 Char)
         col_date_conv  TYPE c LENGTH 19,            " DATE ('YYYY-MM-DD HH24:MI:SS')
         col_date_conv2 TYPE c LENGTH 15,            " DATE ('YYYYMMDD HH24MISS')
       END OF ty_s_tableline.

TYPES: ty_it_table TYPE STANDARD TABLE OF ty_s_tableline WITH DEFAULT KEY.

* DB Connection zur Oracle DB
PARAMETERS: p_dbs TYPE dbcon-con_name DEFAULT 'MYDBCON'.
PARAMETERS: p_par1 type matnr DEFAULT '12345'.
  
START-OF-SELECTION.

* Verbindungsinfos zur DB Connection lesen
  DATA: lv_dbtype TYPE dbcon_dbms.

  SELECT SINGLE dbms
    INTO @lv_dbtype
    FROM dbcon
    WHERE con_name = @p_dbs.

  IF sy-subrc = 0.
* Repräsentiert die Connection eine Oracle-DB?
    IF lv_dbtype = 'ORA'. " Domäne DBCON_DBMS
      TRY.
* Connect to DB
          EXEC SQL.
            CONNECT TO :p_dbs
          ENDEXEC.

          IF sy-subrc = 0.
* Open Cursor and SELECT
* SQL-Statements im ORACLE Syntax!
* Abbildung verschiedener Oracle-Datentypen als ABAP-Datentypen
* speziell das Datum (Orycle Typ DATE) muss Oracleseitig als Character-Feld (z.B. Länge 19 oder 15) interpretiert werden (CAST), damit es korrekt an SAP übertragen werden kann
* zusätzliche Komplexität durch INNER JOIN von zwei Tabellen mytab und mytab2
* Übergabe von Parametern an die EXEC SQL-Bereiche erfolgt immer durch ":Variablenname"
            EXEC SQL.
              OPEN dbcur FOR
              SELECT mytab.col_number,
                     mytab.col_number10_2,
                     mytab2.col_number5,
                     mytab.col_char,
                     CAST (TO_CHAR (mytab.col_date, 'YYYY-MM-DD HH24:MI:SS') AS VARCHAR2 (19)) AS col_date_conv
                     CAST (TO_CHAR (mytab.col_date, 'YYYYMMDD HH24MISS') AS VARCHAR2 (15)) AS col_date_conv2
              FROM myschemaname.mytablename mytab
              INNER JOIN myschemaname.mytablename2 mytab2 ON mytab.key1 = mytab2.key1 AND mytab.key2 = mytab2.key2
              WHERE mytab2.colxyz = :p_par1
            ENDEXEC.

            IF sy-subrc = 0.
              DATA: lv_line TYPE ty_s_tableline.
              DATA: it_table TYPE ty_it_table.

* Loop Cursor Data
              DO.
* DB-Cursor auf nächsten Datensatz setzen, solange, wie Daten vorhanden sind
                EXEC SQL.
                  FETCH NEXT dbcur INTO :lv_line
                ENDEXEC.
                IF sy-subrc = 0.
* Daten an itab anfügen
                  APPEND lv_line TO it_table.
                ELSE.
* keine Daten mehr vorhanden (EOF)
                  EXIT.
                ENDIF.
              ENDDO.

* Close Cursor
              EXEC SQL.
                CLOSE dbcur
              ENDEXEC.

            ENDIF.
* Disconnect
            EXEC SQL.
              DISCONNECT :p_dbs
            ENDEXEC.

* Daten ausgeben
            DATA: o_salv TYPE REF TO cl_salv_table.

            cl_salv_table=>factory( IMPORTING
                                      r_salv_table = o_salv
                                    CHANGING
                                      t_table      = it_table ).

            o_salv->get_functions( )->set_all( abap_true ).
            o_salv->get_columns( )->set_optimize( abap_true ).
            o_salv->get_display_settings( )->set_list_header( 'Oracle Data' ).
            o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
            o_salv->get_selections( )->set_selection_mode( if_salv_c_selection_mode=>row_column ).

            LOOP AT o_salv->get_columns( )->get( ) ASSIGNING FIELD-SYMBOL(<c>).
              <c>-r_column->set_short_text( |{ <c>-r_column->get_columnname( ) }| ).
              <c>-r_column->set_medium_text( |{ <c>-r_column->get_columnname( ) }| ).
              <c>-r_column->set_long_text( |{ <c>-r_column->get_columnname( ) }| ).
            ENDLOOP.

            o_salv->display( ).
          ELSE.
            WRITE: / 'DB-Verbindung konnte nicht hergestellt werden.'.
          ENDIF.
        CATCH cx_root INTO DATA(e_txt).
          WRITE: / e_txt->get_text( ).
      ENDTRY.
    ELSE.
      WRITE: / |Falscher Datenbanktyp: { lv_dbtype }|.
    ENDIF.
  ELSE.
    WRITE: / |DB-Alias { p_dbs } nicht im System vorhanden.|.
  ENDIF.

[ABAP] Zeit zu Zeit und Datum rechnen

DATA: lv_sdate TYPE d.
DATA: lv_stime TYPE t.

* akt. Datum und Zeit
lv_sdate = sy-datum.
lv_stime = sy-uzeit.

* 10:00:00Uhr
DATA: lv_addtime TYPE t VALUE '100000'.

DATA: lv_edate TYPE d.
DATA: lv_etime TYPE t.

START-OF-SELECTION.

* Zeitwerte addieren
  CALL FUNCTION 'C14B_ADD_TIME'
    EXPORTING
      i_starttime = lv_stime
      i_startdate = lv_sdate
      i_addtime   = lv_addtime
    IMPORTING
      e_endtime   = lv_etime
      e_enddate   = lv_edate.

  WRITE: / lv_sdate, lv_stime.
  WRITE: / lv_edate, lv_etime.

[JavaScript] Einfacher Timer

<!doctype html>
<html lang="de">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Timer demo</title>
  </head>
  <body>
    <script>
      'use strict';  
      (function () {
        function timer() {
          let st = Date.now();
          // Intervall 100ms
          setInterval(function() {
            let el = Date.now() - st;
            console.log((el / 1000).toFixed(1));
          }, 100);
        }

        document.addEventListener('DOMContentLoaded', timer);
      }());
    </script>
  </body>
</html>

[JavaScript] Date: Datum und Zeit

// https://www.w3schools.com/jsref/jsref_obj_date.asp
// https://javascript.info/date

// akt. Datum + Uhrzeit
let dt_curr = new Date();
console.log(dt_curr.toString());

// Datum: 31.12.2018, Uhrzeit: 12:10:20,0
// Monat startet mit Index 0!
let d = new Date(2018, 11, 31, 12, 10, 20, 0);

// Mon Dec 31 2018 12:10:20 GMT+0100
console.log(d.toString());
// Mon, 31 Dec 2018 11:10:20 GMT
console.log(d.toUTCString());
// 2018-12-31T11:10:20.000Z
console.log(d.toISOString());
// 31.12.2018, 12:10:20
console.log(d.toLocaleString('de-DE'));
// 31.12.2018
console.log(d.toLocaleDateString('de-DE'));
// 12:10:20
console.log(d.toLocaleTimeString('de-DE'));

// Anzahl Millisekunden, seit 01.01.1970 00:00:00 UTC
console.log(Date.now());

[ABAP] UTC-Zeit (TIMESTAMP) in Datum (d) und Uhrzeit (t) splitten

DATA: lv_date TYPE d.
DATA: lv_time TYPE t.
DATA: lv_utc TYPE timestamp.

GET TIME STAMP FIELD lv_utc.

* Zeitzohne bleibt UTC, Timestamp wird also ohne Umrechnung der Zone gesplittet
CONVERT TIME STAMP lv_utc TIME ZONE 'UTC' INTO DATE lv_date TIME lv_time.

WRITE: / |UTC: { lv_utc TIMESTAMP = USER }|.
WRITE: / |UTC-Datum: { lv_date DATE = USER }|.
WRITE: / |UTC-Zeit: { lv_time TIME = USER }|.

[ABAP] UTC-Zeit (TIMESTAMP) in Systemzeit wandeln

DATA: lv_utc TYPE timestamp.
DATA: lv_date TYPE d.
DATA: lv_time TYPE t.

START-OF-SELECTION.

  GET TIME STAMP FIELD lv_utc.

  TRY.
      cl_abap_tstmp=>systemtstmp_utc2syst( EXPORTING
                                             utc_tstmp = lv_utc
                                           IMPORTING
                                             syst_date = lv_date
                                             syst_time = lv_time  ).

      WRITE: / |UTC: { lv_utc TIMESTAMP = USER }|.
      WRITE: / |System-Datum: { lv_date DATE = USER }|.
      WRITE: / |System-Zeit: { lv_time TIME = USER }|.

    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.