Перейти до вмісту

Дата, час і час-мітка

Робота з датами і часом в ABAP зав’язана на кілька типів з різною семантикою: d і t — символьні (зберігаються як текст), utclong — 8-байтове ціле з точністю до 100 нс у UTC, timestamp/timestampl — packed-числа у форматі yyyymmddhhmmss[.sssssss]. Вибір типу визначає і доступні операції, і поведінку при обчисленнях.

Загальне правило: у новому коді для time stamp бери utclong, для дат у БД — datn, для часу — timn. Старі dats/tims вимагають конвертації. В ABAP Cloud системні поля sy-datum, sy-uzeit не використовуй — дані бери через cl_abap_context_info або XCO.

ТипДовжинаФорматЩо всередині
d8 символівyyyymmddдата Григоріанського календаря
t6 символівhhmmss24-годинний час
utclong8 байтціле числоUTC time stamp, 100 нс, від 0001-01-01T00:00:00.0000000 до 9999-12-31T23:59:59.9999999
timestamppackedyyyymmddhhmmsstime stamp без часток секунди
timestamplpackedyyyymmddhhmmss.ssssssstime stamp з 7 десятковими
DATA some_date TYPE d VALUE '20240101'.
DATA(some_time) = CONV t( '123456' ).
FINAL(utc_ts) = CONV utclong( '2024-01-01 15:30:00' ).
DATA ts_short TYPE timestamp VALUE '20240101082802'.
DATA ts_long TYPE timestampl VALUE '20240101082802.1700020'.
TRY.
DATA(tz) = cl_abap_context_info=>get_user_time_zone( ).
CATCH cx_abap_context_info_error.
ENDTRY.
" Через XCO
DATA(tz_user) = xco_cp_time=>time_zone->user->value.
DATA(tz_utc) = xco_cp_time=>time_zone->utc->value.

У SAP BTP ABAP Environment time zone за замовчуванням — UTC. Користувацьку зону налаштовують у Fiori Launchpad.

" Поточна дата у UTC, тип d (e.g. 20240101)
DATA(utc_date) = cl_abap_context_info=>get_system_date( ).
" Через XCO — результат типу string
DATA(date_abap) = xco_cp=>sy->date( )->as( xco_cp_time=>format->abap )->value. "20250101
DATA(date_basic) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_basic )->value. "20250101
DATA(date_ext) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value. "2025-01-01
" Явне вказання time zone
DATA(date_user) = xco_cp=>sy->date( xco_cp_time=>time_zone->user
)->as( xco_cp_time=>format->iso_8601_basic )->value.
" Компоненти поточної дати
DATA(day) = xco_cp=>sy->date( )->day. "01
DATA(month) = xco_cp=>sy->date( )->month. "01
DATA(year) = xco_cp=>sy->date( )->year. "2024
" Створення дати
DATA date1 TYPE d VALUE '20240101'.
DATA(date2) = CONV d( '20240303' ).
DATA(xco_date) = xco_cp_time=>date( iv_year = 2024 iv_month = 3 iv_day = 3 ).
" Lossless — викидає виняток на некоректне значення
TRY.
DATA(inv1) = EXACT d( '20240231' ).
CATCH cx_sy_conversion_no_date.
ENDTRY.
" Без EXACT — тиха конверсія у 0
DATA(zero) = CONV i( CONV d( '20240231' ) ). " 0
DATA some_date TYPE d VALUE '20240102'.
" Через substring
DATA(year_sub) = substring( val = some_date off = 0 len = 4 ). "2024
DATA(month_sub) = substring( val = some_date off = 4 len = 2 ). "01
" Offset-доступ
DATA(year_off) = some_date(4). "2024
DATA(month_off) = some_date+4(2). "01
DATA(day_off) = some_date+6(2). "02
" Запис через offset
some_date+4(2) = '10'. " 20241002

Дата конвертується у число днів від 01.01.0001. Віднімання дат повертає різницю в днях.

DATA d1 TYPE d VALUE '20240101'.
DATA d2 TYPE d VALUE '20231227'.
DATA(days_diff) = d1 - d2. " 5
DATA(days_from_epoch) = CONV i( d1 ). " 738887
DATA(weekday) = ( 5 + d1 MOD 7 ) MOD 7 + 1. " 1 = понеділок
" Перший день місяця + останній день попереднього
DATA(first_of_month) = CONV d( replace( val = `20240302` off = 6 len = 2 with = `01` ) ).
DATA(last_of_prev) = CONV d( first_of_month - 1 ). " 20240229
" Додати 5 днів
DATA(plus5) = xco_cp=>sy->date( )->add( iv_day = 5
)->as( xco_cp_time=>format->iso_8601_extended )->value.
" Рік/місяць/день одразу
DATA(plus1_all) = xco_cp=>sy->date( )->add( iv_day = 1 iv_month = 1 iv_year = 1
)->as( xco_cp_time=>format->iso_8601_extended )->value.
" Субтракція
DATA(minus_all) = xco_cp=>sy->date( )->subtract( iv_day = 1 iv_month = 1 iv_year = 1
)->as( xco_cp_time=>format->iso_8601_extended )->value.

add/subtract мають параметр io_calculation:

  • xco_cp_time=>date_calculation->preserving (default) — математичне обчислення, на некоректному результаті виняток.
  • xco_cp_time=>date_calculation->ultimo — якщо результат невалідний (наприклад, 31 серпня + 1 місяць = 31 вересня), береться останній день місяця.
" 2024-08-31 + 1 місяць з ultimo → 2024-09-30
DATA(ultimo) = xco_cp_time=>date( iv_year = '2024' iv_month = '08' iv_day = '31'
)->add( iv_month = 1
io_calculation = xco_cp_time=>date_calculation->ultimo
)->as( xco_cp_time=>format->iso_8601_extended )->value.

Конвертації формату: CL_ABAP_DATFM

Section titled “Конвертації формату: CL_ABAP_DATFM”

Клас cl_abap_datfm конвертує дати між внутрішнім d і зовнішніми форматами (DD.MM.YYYY, MM/DD/YYYY, ISO YYYY-MM-DD, японський, ісламський, іранський).

DATA(internal) = CONV d( '20240202' ).
DATA ext TYPE string.
DATA fmt_used TYPE cl_abap_datfm=>ty_datfm.
TRY.
cl_abap_datfm=>conv_date_int_to_ext(
EXPORTING im_datint = internal
im_datfmdes = '6' " YYYY-MM-DD (ISO)
IMPORTING ex_datext = ext " '2024-02-02'
ex_datfmused = fmt_used ).
CATCH cx_abap_datfm_format_unknown.
ENDTRY.
" Зворотна конвертація
DATA internal2 TYPE d.
TRY.
cl_abap_datfm=>conv_date_ext_to_int(
EXPORTING im_datext = ext
im_datfmdes = '6'
IMPORTING ex_datint = internal2 ).
CATCH cx_abap_datfm_no_date cx_abap_datfm_invalid_date
cx_abap_datfm_format_unknown cx_abap_datfm_ambiguous.
ENDTRY.
" Поточний формат користувача і формат країни
DATA(datfm) = cl_abap_datfm=>get_datfm( ).
DATA(country_datfm) = cl_abap_datfm=>get_country_datfm( 'DE' ).

Коди форматів: 1 (DD.MM.YYYY), 2 (MM/DD/YYYY), 3 (MM-DD-YYYY), 4 (YYYY.MM.DD), 5 (YYYY/MM/DD), 6 (YYYY-MM-DD ISO), 79 (японський), AB (ісламський), C (іранський).

DATA(utc_time) = cl_abap_context_info=>get_system_time( ). " e.g. 152450
DATA(time_ext) = xco_cp=>sy->time( )->as( xco_cp_time=>format->iso_8601_extended )->value. "16:09:07
DATA(time_basic) = xco_cp=>sy->time( )->as( xco_cp_time=>format->iso_8601_basic )->value. "160907
" Створення
DATA time1 TYPE t VALUE '112400'.
DATA(time2) = CONV t( '120000' ).
DATA(xco_time) = xco_cp_time=>time( iv_hour = '08' iv_minute = '34' iv_second = '05' ).
DATA(sec) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->second.
DATA(min) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->minute.
DATA(hr) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->hour.

t конвертується у число секунд від 00:00:00. Різниця може бути негативною — якщо перетинає північ.

DATA t1 TYPE t VALUE '210000'.
DATA t2 TYPE t VALUE '040000'.
DATA(diff) = t2 - t1. " -61200 (секунд)
DATA(diff_pos) = ( t2 - t1 ) MOD 86400. " 25200 — абсолютна різниця в секундах за добу
" Розкладка секунд на години/хвилини/секунди
DATA(total) = ( t2 - t1 ) MOD 86400.
DATA(hours) = total DIV 3600.
DATA(rem) = total MOD 3600.
DATA(minutes) = rem DIV 60.
DATA(seconds) = rem MOD 60.
DATA result TYPE t.
result(2) = hours.
result+2(2) = minutes.
result+4(2) = seconds. " '070000'
DATA(plus1) = xco_cp=>sy->time( xco_cp_time=>time_zone->user
)->add( iv_hour = 1 iv_minute = 1 iv_second = 1
)->as( xco_cp_time=>format->iso_8601_extended )->value.
DATA(minus1) = xco_cp=>sy->time( xco_cp_time=>time_zone->user
)->subtract( iv_hour = 1 iv_minute = 1 iv_second = 1
)->as( xco_cp_time=>format->iso_8601_extended )->value.
DATA(int_time) = CONV t( '123456' ).
DATA ext_time TYPE string.
TRY.
cl_abap_timefm=>conv_time_int_to_ext(
EXPORTING time_int = int_time
without_seconds = abap_false
format_according_to = cl_abap_timefm=>iso " hh:mm:ss
IMPORTING time_ext = ext_time ). " '12:34:56'
CATCH cx_parameter_invalid_range.
ENDTRY.
" Поточний time stamp
DATA(ts1) = utclong_current( ). " 2024-01-01 15:45:46.2695940
" XCO
DATA(ts_ext) = xco_cp=>sy->moment( )->as( xco_cp_time=>format->iso_8601_extended )->value.
" Створення
DATA ts2 TYPE utclong VALUE '2024-11-05 15:30:00'.
DATA(ts3) = CONV utclong( '2024-11-03 05:30:00' ).
DATA(ts_xco) = xco_cp_time=>moment( iv_year = '2024' iv_month = '01' iv_day = '01'
iv_hour = '12' iv_minute = '34' iv_second = '55'
)->as( xco_cp_time=>format->iso_8601_extended )->value.

Параметрів для місяців і років немає — тільки days, hours, minutes, seconds. Віднімання — через від’ємний параметр (окремої функції немає).

DATA(base) = CONV utclong( '2024-01-01 15:55:14.1173220' ).
DATA(plus_hour) = utclong_add( val = base hours = 1 ). " +1 година
DATA(minus_hour) = utclong_add( val = base hours = -1 ). " -1 година
DATA(combined) = utclong_add( val = base
days = 1
hours = 2
minutes = CONV int8( '13' )
seconds = CONV decfloat34( '53.12' ) ).
DATA(low) = CONV utclong( '2024-01-01 05:30:00' ).
DATA(high) = CONV utclong( '2024-01-01 06:30:00' ).
" Повертає decfloat34 — різницю в секундах
DATA(diff_pos) = utclong_diff( high = high low = low ). " 3600
DATA(diff_neg) = utclong_diff( high = low low = high ). " -3600
DATA(end_ts) = xco_cp_time=>moment( iv_year = '2030' iv_month = '01' iv_day = '01'
iv_hour = '10' iv_minute = '00' iv_second = '00' ).
DATA(check_ts) = xco_cp_time=>moment( iv_year = '2028' iv_month = '01' iv_day = '01'
iv_hour = '11' iv_minute = '00' iv_second = '00' ).
DATA(interval) = xco_cp=>sy->moment( )->interval_to( end_ts ).
DATA(is_in) = interval->contains( check_ts ). " abap_bool
DATA(low_b) = interval->lower_bound->as( xco_cp_time=>format->iso_8601_extended )->value.
DATA(up_b) = interval->upper_bound->as( xco_cp_time=>format->iso_8601_extended )->value.

Конвертація utclong ↔ локальні дата/час

Section titled “Конвертація utclong ↔ локальні дата/час”
DATA ts TYPE utclong VALUE '2024-11-03 05:30:00'.
" utclong → локальні дата/час у заданій TZ
CONVERT UTCLONG ts
INTO DATE DATA(d_local) " 20241103
TIME DATA(t_local) " 013000
TIME ZONE 'EST'.
" З fractional seconds і DST-прапорцем
CONVERT UTCLONG CONV utclong( '2024-08-08 09:23:11.7681270' )
INTO DATE d_local
TIME t_local
FRACTIONAL SECONDS DATA(frac) " 0.768127
DAYLIGHT SAVING TIME DATA(dst) " 'X'
TIME ZONE 'EST'.
" Зворотний напрямок: локальні → utclong
DATA d_in TYPE d VALUE '20240101'.
DATA t_in TYPE t VALUE '112458'.
DATA utcl TYPE utclong.
CONVERT DATE d_in TIME t_in TIME ZONE 'EST' INTO UTCLONG utcl.
" 2024-01-01 16:24:58.0000000
DATA(low) = CONV utclong( '2024-01-01 05:30:00' ).
DATA(high) = CONV utclong( '2024-01-03 10:35:12' ).
" Різниця з розкладкою
cl_abap_utclong=>diff(
EXPORTING high = high low = low
IMPORTING days = DATA(dd) " 2
hours = DATA(hh) " 5
minutes = DATA(mm) " 5
seconds = DATA(ss) ). " 12
" Парсинг utclong з рядка
DATA(ts_str) = |{ utclong_current( ) TIMESTAMP = ENVIRONMENT TIMEZONE = 'UTC' }|.
TRY.
cl_abap_utclong=>read( EXPORTING string = ts_str
timezone = 'UTC'
IMPORTING value = DATA(parsed) ).
CATCH cx_abap_utclong_invalid.
ENDTRY.

Packed-number time stamps (timestamp / timestampl)

Section titled “Packed-number time stamps (timestamp / timestampl)”

Це старий тип. У новому коді — utclong, але він ще живий у багатьох API.

DATA ts_s TYPE timestamp.
GET TIME STAMP FIELD ts_s. " 20240101081317
DATA ts_l TYPE timestampl.
GET TIME STAMP FIELD ts_l. " 20240101081317.81011
" Inline — завжди timestamp (short)
GET TIME STAMP FIELD DATA(ts_inl).

Конвертація у локальні дата/час:

CONVERT TIME STAMP ts_s
TIME ZONE 'EST'
INTO DATE DATA(dd) TIME DATA(tt).
" sy-subrc: 0 — ок, 8 — невалідна зона, 12 — невалідний time stamp

Зворотна конвертація — CONVERT DATE ... TIME ... INTO TIME STAMP ... TIME ZONE ....

Клас cl_abap_tstmp для обчислень і конвертацій між packed і utclong:

GET TIME STAMP FIELD DATA(ts_a).
DATA(ts_plus_hr) = cl_abap_tstmp=>add( tstmp = ts_a secs = 3600 ).
DATA(ts_minus_2h) = cl_abap_tstmp=>subtractsecs( tstmp = ts_a secs = 7200 ).
" Конвертації між форматами
DATA(ts_short) = cl_abap_tstmp=>move_to_short( ts_l ). " timestampl → timestamp
DATA(ts_utclong) = cl_abap_tstmp=>tstmp2utclong( ts_l ). " → utclong
DATA(ts_back_s) = cl_abap_tstmp=>utclong2tstmp_short( ts_utclong ).
DATA(ts_back_l) = cl_abap_tstmp=>utclong2tstmp( ts_utclong ).
" Поточний Unix time stamp (секунди з 1970-01-01 UTC)
DATA(unix_now) = xco_cp=>sy->unix_timestamp( )->value.
" З довільної дати
DATA(unix_custom) = xco_cp_time=>moment( iv_year = '2024' iv_month = '11' iv_day = '03'
iv_hour = '07' iv_minute = '12' iv_second = '30'
)->get_unix_timestamp( )->value. " 1730617950
" Unix → utclong
DATA(from_unix) = utclong_add( val = CONV utclong( '1970-01-01 00:00:00' )
seconds = 1730617950 ). " 2024-11-03 07:12:30.0000000

У string templates дати, часи і time stamps форматуються спеціальними опціями:

DATA(d) = cl_abap_context_info=>get_system_date( ).
DATA(t) = cl_abap_context_info=>get_system_time( ).
DATA(u) = utclong_current( ).
" DATE
|{ d DATE = USER }| " 01/01/2024
|{ d DATE = RAW }| " 20240101
|{ d DATE = ISO }| " 2024-01-01
|{ d DATE = ENVIRONMENT }|
" TIME
|{ t TIME = ISO }| " 14:37:24
|{ t TIME = RAW }| " 143724
|{ t TIME = USER }|
" TIMESTAMP
|{ u TIMESTAMP = SPACE }| " 2024-01-01 14:39:50.4069170
|{ u TIMESTAMP = ISO }| " 2024-01-01T14:39:50,4071110
|{ u TIMESTAMP = ENVIRONMENT }|
" TIMEZONE + COUNTRY
|{ u TIMEZONE = 'CET' COUNTRY = 'DE' }| " 30.12.2024 15:43:20,6536320
|{ u TIMEZONE = 'EST' COUNTRY = 'US' }| " 12/30/2024 09:43:20.6889180 AM

Функції дати/часу в ABAP SQL та CDS

Section titled “Функції дати/часу в ABAP SQL та CDS”

Набір функцій у ABAP SQL і CDS однаковий. Базові — generic (працюють з d, utclong), є специфічні для datn, dats, timn, tims, timestamp, utclong.

SELECT SINGLE FROM i_timezone FIELDS
" --- Дата ---
is_valid( @da ) AS isvalid,
extract_year( @utc ) AS yr,
extract_month( @da ) AS mo,
extract_day( @utc ) AS dy,
dayname( @da ) AS day_name, " Monday
monthname( @utc ) AS month_name, " February
weekday( @utc ) AS week_day, " 3
days_between( @utc, utclong`2024-02-25 08:14:26` ) AS days_bw,
add_days( @da, 2 ) AS plus_days,
add_months( @utc, 3 ) AS plus_months,
" --- Специфічні для datn/dats ---
datn_days_between( datn`20240111`, datn`20240212` ) AS dbtw,
datn_add_days( datn`20240111`, 4 ) AS dadd,
dats_is_valid( dats`20240812` ) AS dvalid,
" --- Час ---
extract_hour( @utc ) AS hr,
extract_minute( @ti ) AS mi,
tims_is_valid( tims`231256` ) AS tvalid,
" --- Time stamp ---
utcl_current( ) AS now,
utcl_add_seconds( @utc, 5 ) AS plus5s,
utcl_seconds_between( utclong`2024-02-25 08:14:26`, utclong`2024-02-25 08:15:17` ) AS sbtw,
tstmp_is_valid( @tmst ) AS tsv,
tstmp_current_utctimestamp( ) AS tsnow,
" --- Конвертації ---
tstmp_to_dats( tstmp = @tmst, tzone = CAST( char`EST` AS CHAR( 6 ) ) ) AS to_dats,
tstmp_to_tims( tstmp = @tmst, tzone = CAST( char`EST` AS CHAR( 6 ) ) ) AS to_tims,
tstmp_to_dst( tstmp = @tmst, tzone = CAST( char`EST` AS CHAR( 6 ) ) ) AS to_dst,
dats_tims_to_tstmp( date = @da, time = @ti,
tzone = CAST( char`EST` AS CHAR( 6 ) ) ) AS combine,
tstmpl_to_utcl( tstmpl = @tmstlong ) AS to_utcl,
tstmpl_from_utcl( utcl = @utc ) AS from_utcl
WHERE TimeZoneID = char`EST`
INTO @DATA(wa).

Адаптовано з 23_Date_and_Time.md (Apache 2.0). Повний перелік нюансів — в оригіналі.