Дата, час і час-мітка
Робота з датами і часом в 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.
Типи даних
Section titled “Типи даних”| Тип | Довжина | Формат | Що всередині |
|---|---|---|---|
d | 8 символів | yyyymmdd | дата Григоріанського календаря |
t | 6 символів | hhmmss | 24-годинний час |
utclong | 8 байт | ціле число | UTC time stamp, 100 нс, від 0001-01-01T00:00:00.0000000 до 9999-12-31T23:59:59.9999999 |
timestamp | packed | yyyymmddhhmmss | time stamp без часток секунди |
timestampl | packed | yyyymmddhhmmss.sssssss | time 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'.Часова зона
Section titled “Часова зона”TRY. DATA(tz) = cl_abap_context_info=>get_user_time_zone( ). CATCH cx_abap_context_info_error.ENDTRY.
" Через XCODATA(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.
Отримання і створення
Section titled “Отримання і створення”" Поточна дата у UTC, тип d (e.g. 20240101)DATA(utc_date) = cl_abap_context_info=>get_system_date( ).
" Через XCO — результат типу stringDATA(date_abap) = xco_cp=>sy->date( )->as( xco_cp_time=>format->abap )->value. "20250101DATA(date_basic) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_basic )->value. "20250101DATA(date_ext) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value. "2025-01-01
" Явне вказання time zoneDATA(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. "01DATA(month) = xco_cp=>sy->date( )->month. "01DATA(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 ).Валідність
Section titled “Валідність”" Lossless — викидає виняток на некоректне значенняTRY. DATA(inv1) = EXACT d( '20240231' ). CATCH cx_sy_conversion_no_date.ENDTRY.
" Без EXACT — тиха конверсія у 0DATA(zero) = CONV i( CONV d( '20240231' ) ). " 0Доступ як до рядка
Section titled “Доступ як до рядка”DATA some_date TYPE d VALUE '20240102'.
" Через substringDATA(year_sub) = substring( val = some_date off = 0 len = 4 ). "2024DATA(month_sub) = substring( val = some_date off = 4 len = 2 ). "01
" Offset-доступDATA(year_off) = some_date(4). "2024DATA(month_off) = some_date+4(2). "01DATA(day_off) = some_date+6(2). "02
" Запис через offsetsome_date+4(2) = '10'. " 20241002Арифметика з датами
Section titled “Арифметика з датами”Дата конвертується у число днів від 01.01.0001. Віднімання дат повертає різницю в днях.
DATA d1 TYPE d VALUE '20240101'.DATA d2 TYPE d VALUE '20231227'.
DATA(days_diff) = d1 - d2. " 5DATA(days_from_epoch) = CONV i( d1 ). " 738887DATA(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 ). " 20240229XCO для арифметики дат
Section titled “XCO для арифметики дат”" Додати 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-30DATA(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), 7–9 (японський), A–B (ісламський), C (іранський).
Отримання і створення
Section titled “Отримання і створення”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:07DATA(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.Арифметика з часом
Section titled “Арифметика з часом”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'XCO для арифметики часу
Section titled “XCO для арифметики часу”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.CL_ABAP_TIMEFM
Section titled “CL_ABAP_TIMEFM”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
Section titled “Time stamp”utclong — сучасний підхід
Section titled “utclong — сучасний підхід”" Поточний time stampDATA(ts1) = utclong_current( ). " 2024-01-01 15:45:46.2695940
" XCODATA(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.Додавання через utclong_add
Section titled “Додавання через utclong_add”Параметрів для місяців і років немає — тільки 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' ) ).Різниця через utclong_diff
Section titled “Різниця через utclong_diff”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 ). " 3600DATA(diff_neg) = utclong_diff( high = low low = high ). " -3600XCO: інтервали і contains
Section titled “XCO: інтервали і contains”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_boolDATA(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 → локальні дата/час у заданій TZCONVERT 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'.
" Зворотний напрямок: локальні → utclongDATA 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.0000000CL_ABAP_UTCLONG
Section titled “CL_ABAP_UTCLONG”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 → timestampDATA(ts_utclong) = cl_abap_tstmp=>tstmp2utclong( ts_l ). " → utclongDATA(ts_back_s) = cl_abap_tstmp=>utclong2tstmp_short( ts_utclong ).DATA(ts_back_l) = cl_abap_tstmp=>utclong2tstmp( ts_utclong ).Unix time stamp
Section titled “Unix time stamp”" Поточний 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 → utclongDATA(from_unix) = utclong_add( val = CONV utclong( '1970-01-01 00:00:00' ) seconds = 1730617950 ). " 2024-11-03 07:12:30.0000000String-шаблони
Section titled “String-шаблони”У 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_utclWHERE TimeZoneID = char`EST`INTO @DATA(wa).Адаптовано з 23_Date_and_Time.md (Apache 2.0). Повний перелік нюансів — в оригіналі.