среда, 12 марта 2014 г.

SAP ABAP функции для работы с датой и временем

В данной теме хочется поговорить о функциях работы с датами.
Очень часто в своих разработках мы используем данные функции п.э. далее перечислим самые популярные и полезные на мой взгляд.

Даты передается и возвращается в стандартном формате типа SY-DATUM (YYYYMMDD, YYYY - Год, MM - Месяц, DD - День):

data: begda like sy-datum,
        endda like sy-datum.

Я думаю все знают как получить первый день месяца.

CONCATENATE YYYY MM  '01' into begda.

* Возвращает последний день месяца в формате YYYYMMDD (YYYY - Год, MM - Месяц, DD - День).


  CALL FUNCTION 'LAST_DAY_OF_MONTHS'
    EXPORTING      
            DAY_IN                                begda     
   IMPORTING      
          LAST_DAY_OF_MONTH endda    
 EXCEPTIONS      
          DAY_IN_NO_DATE    1      
          OTHERS            2.

Определение номера недели для даты в формате YYYYWW (YYYY - Год, WW - Неделя):
DATA: l_week LIKE scal-week.
                                                                       
CALL FUNCTION  'DATE_GET_WEEK'
     EXPORTING
          date         = sy-datum
     IMPORTING
          week         = l_week
     EXCEPTIONS
          date_invalid = 1
          OTHERS       = 2.

* Возвращает дату, с которой начинается неделя по ее номеру. Номер недели в формате YYYYWW (YYYY - Год, WW - Неделя). Дата в стандартном формате типа SY-DATUM (YYYYMMDD, YYYY - Год, MM - Месяц, DD - День):
DATA: l_week LIKE scal-week,
      l_datum like sy-datum.

CALL FUNCTION 'WEEK_GET_FIRST_DAY'
  EXPORTING
    week               = l_week
 IMPORTING
   DATE               = l_datum
 EXCEPTIONS
   WEEK_INVALID       = 1
   OTHERS             = 2.

Преобразование внутреннего представления даты в стандартный вид типа SY-DATUM. Знаю только одну ситуацию, где используется такое, это таблица курсов валют TCURR, там все даты заданы именно во внутреннем формате. Передается дата в формате вида TCURR-GDATU, а возвращается стандартное представление типа SY-DATUM (YYYYMMDD, YYYY - Год, MM - Месяц, DD - День):
DATA:  l_datum LIKE sy-datum,
      l_gdatu LIKE tcurr-gdatu.

l_gdatu = '79948998'.
CALL FUNCTION 'DATE_CONV_EXT_TO_INT'
     EXPORTING
          i_date_ext = l_gdatu
     IMPORTING
          e_date_int = l_datum
     EXCEPTIONS
          error      = 1
          OTHERS     = 2.


* Дата начала периода к варианту финансового года. Стандартные параметры - год вида YYYY. Вариант финансового года для БЕ в виде CC. Номер требуемого периода задается в формате NNN. Возвращаемая дата представлена в стандартном типе SY-DATUM (YYYYMMDD, YYYY - Год, MM - Месяц, DD - День). Стандартно как бы используется практически везде вариант финансового года K4 - т.е.  4 квартала. Если пишем универсальную программу, то начало периода лучше считать используя данный ФМ:
DATA: l_gjahr LIKE t009b-bdatj,
      l_periv LIKE t009b-periv,
      l_poper LIKE t009b-poper,
      l_datum LIKE sy-datum.
                                                                        
l_gjahr = '2007'.
l_periv = 'K4'.
l_poper = '002'.
CALL FUNCTION 'FIRST_DAY_IN_PERIOD_GET'
     EXPORTING
          i_gjahr        = l_gjahr
*         I_MONMIT             = 00
          i_periv        = l_periv
          i_poper        = l_poper
     IMPORTING
          e_date         = l_datum
     EXCEPTIONS
          input_false    = 1
          t009_notfound  = 2
          t009b_notfound = 3
          OTHERS         = 4.


* Дата конца периода к варианту финансового года. Стандартные параметры - год вида YYYY. Вариант финансового года для БЕ в виде CC. Номер требуемого периода задается в формате NNN. Возвращаемая дата представлена в стандартном типе SY-DATUM (YYYYMMDD, YYYY - Год, MM - Месяц, DD - День). Собственно причина почему её желательно использовать такая же как и для предыдущего функционального модуля FIRST_DAY_IN_PERIOD_GET:
DATA: l_gjahr LIKE t009b-bdatj,
      l_periv LIKE t009b-periv,
      l_poper LIKE t009b-poper,
      l_datum LIKE sy-datum.
                                                                        
l_gjahr = '2007'.
l_periv = 'K4'.
l_poper = '002'.
CALL FUNCTION 'LAST_DAY_IN_PERIOD_GET'
     EXPORTING
          i_gjahr        = l_gjahr
*         I_MONMIT             = 00
          i_periv        = l_periv
          i_poper        = l_poper
     IMPORTING
          e_date         = l_datum
     EXCEPTIONS
          input_false    = 1
          t009_notfound  = 2
          t009b_notfound = 3
          OTHERS         = 4.

* Дата через NN-Дней, MM-Месяцев и YY-Лет от заданной. При этом можно как суммировать так и отнимать требуемое количество дней, месяцев и лет. О високосном годе, вроде, как тоже знает. Из полезного можно добавлять например 55 дней и 1 месяц и т.д. Если даты нужно отнимать, тогда нужно задать параметр SIGNUM = '-':
DATA: l_days LIKE t5a4a-dlydy,
      l_months LIKE t5a4a-dlymo,
      l_years LIKE t5a4a-dlyyr,
      l_datum LIKE sy-datum.
                                                                        
l_days = '10'.
l_month = '05'.
l_years = '02'
call function 'RP_CALC_DATE_IN_INTERVAL'
     exporting
          date      = sy-datum
          days      = l_days
          months    = l_months
          signum    = '+'
          years     = l_years
     importing
          calc_date = l_datum.
В данном вызове для даты 01.02.2007 будет возвращена дата 11.07.2009.



* Разница в днях и часах между двумя произвольно заданными датами. Дата и время начала и конца диапазона задаются в стандартном типе SY-DATUM (YYYYMMDD, YYYY - Год, MM - Месяц, DD - День). Из особенностей работы:
  1. Разница вычисляется только для полного количества часов, т.е. между 01:00 и 02:30 будет возвращено все равно 1 час.
  2. Обязательно нужно задавать поля времени, например хотя бы 1 минута, иначе функция ничего не вернет (Спасибо индусам за наше счастливое детство, но оказывается в этой Индии 00:00:00 времени не бывает в принципе).
  3. Даты можно задавать как от большей к меньшей так и наоборот, при этом переменная l_earliest будет содержать следующие значения =2 - дата1 больше даты2, =1 - дата1 меньше дата2, если даты равны, тогда сравниваются времена и =2 - время1 больше времени2 и =1 - время 1 меньше времени2, если даты и время совпадают, тогда переменная = 0.
DATA: l_datum_one LIKE sy-datum,
      l_time_one LIKE sy-uzeit,
      l_datum_two LIKE sy-datum,
      l_time_two LIKE sy-uzeit.
DATA: l_datediff TYPE p,
      l_timediff TYPE p,
      l_earliest TYPE  c.
                                                                        
CALL FUNCTION 'SD_DATETIME_DIFFERENCE'
     EXPORTING
          date1            = l_datum_one
          time1            = l_time_on
          date2            = l_datum_two
          time2            = l_time_two
     IMPORTING
          datediff         = l_datediff
          timediff         = l_timediff
          earliest         = l_earliest
     EXCEPTIONS
          invalid_datetime = 1
          OTHERS           = 2.

* Возвращает внутреннюю таблицу со списком, как сокращенных наименований месяцев (3 символа), так и полных, в именительном падеже на заданном языке. По умолчанию, используется язык регистрации в системе:
DATA: l_retcode LIKE like sy-subrc,
      lt_month LIKE t247 OCCURS 1 WITH HEADER LINE.
                                                                        
CALL FUNCTION 'MONTH_NAMES_GET'
     EXPORTING
          language              = sy-langu
     IMPORTING
          return_code           = l_retcode
     TABLES
          month_names           = lt_month
     EXCEPTIONS
          month_names_not_found = 1
          OTHERS                = 2.

Так же есть еще одна хорошая функция попоиску имени месяца в именительном и родительном падеже: 
DATA: period(2TYPE n,
      month_name(25type c.

   CALL FUNCTION 'HR_PAY_UA_MONTH_NAME'
    EXPORTING
      MONTHNUM period
    IMPORTING
      MN_NOM   month_name.

* Возвращает в заданном диапазоне список выходных/праздничных дней для выбранного производственного и праздничного календаря. Праздничные и выходные дни берутся из настройки соответствующих календарей, так что если там пусто, то и список будет пустой. Если заданные календари не найдены тогда l_returncode = '4':
DATA: l_holiday_calendar LIKE scal-hcalid,
      l_factory_calendar LIKE scal-fcalid,
      l_date_from LIKE scal-date,
      l_date_to LIKE scal-date,
      l_year_of_valid_from LIKE scal-year,
      l_year_of_valid_to LIKE scal-year,
      l_returncode LIKE sy-subrc,
      lt_holidays LIKE iscal_day OCCURS 1 WITH HEADER LINE.
                                                                        
l_factory_calendar = 'UA'.
l_holiday_calendar = 'UA'
l_date_from = '18.07.2007'.
l_date_to = '18.07.2007'.
CALL FUNCTION 'HOLIDAY_GET'
     EXPORTING
          holiday_calendar           = l_holiday_calendar
          factory_calendar           = l_factory_calendar
          date_from                  = l_date_from
          date_to                    = l_date_to
     IMPORTING
          year_of_valid_from         = l_year_of_valid_from
          year_of_valid_to           = l_year_of_valid_to
          returncode                 = l_returncode
     TABLES
          holidays                   = lt_holidays
     EXCEPTIONS
          factory_calendar_not_found = 1
          holiday_calendar_not_found = 2
          date_has_invalid_format    = 3
          date_inconsistency         = 4
          OTHERS                     = 5.
Формат вывода таблички lt_holidays, для приведенного пример следующий:
DATEFHHOLTXT_SHORTTXT_LONG
28.06.2007XX168День констДень конституції
24.08.2007XX169День НезалДень Незалежності
01.01.2008XX171Новий РікНовий Рік
07.01.2008XX172Різдво ХриРіздво Христово
01.05.2008XX1631 Травня1 Травня
02.05.2008XX1642 Травня2 Травня
09.05.2008XX170День ПеремДень Перемоги



* Позволяет получить информацию о статусе рабочего дня исходя из данных производственного календаря, присвоенного заводу. При этом, если день не является рабочим, то функция вернет следующий рабочий день в зависимости от параметров.
CORRECT_OPTION= '+' - Будет возвращен следующий рабочий день
= '-' - Будет возвращен предыдущий рабочий день
DATE= Дата которую требуется проверить
FACTORY_CALENDAR_ID= Код производственного календаря из T001W
DATA: l_date LIKE scal-date,
      l_factorydate LIKE scal-facdate,
      l_workingday_indicator LIKE scal-indicator.

CALL FUNCTION 'DATE_CONVERT_TO_FACTORYDATE'
     EXPORTING
          correct_option               = '+'
          date                         = sy-datum
          factory_calendar_id          = 'RU'
     IMPORTING
          date                         = l_date
          factorydate                  = l_factorydate
          workingday_indicator         = l_workingday_indicator
     EXCEPTIONS
          calendar_buffer_not_loadable = 1
          correct_option_invalid       = 2
          date_after_range             = 3
          date_before_range            = 4
          date_invalid                 = 5
          factory_calendar_not_found   = 6
          OTHERS                       = 7.  
Результат:
DATE= Дата формата SY-DATUM
FACTORYDATE= Дата во внутреннем формате виде TCURR-GDATU, полезно для чтения курса валюты например.
WORKINGDAY_INDICATOR
= В принципе в нем возвращается значение, которое передается в CORRECT_OPTION, что видно из кода
CASE CORRECT_OPTION.
    WHEN '+'.
        WORKINGDAY_INDICATOR = '+'.
    WHEN '-'.
        WORKINGDAY_INDICATOR = '-'.
ENDCASE.
Правда зачем так сложно, через CASE сделано, это нам наверное никто не подскажет, ну хотя может найдется тот индус, который это писал, а так может были какие мысли, да так и не реализовались.



* Номер дня в неделе, понедельник считается первым днем, воскресение 7.
DATA: l_day LIKE scal-indicator.

CALL FUNCTION 'DATE_COMPUTE_DAY'
     EXPORTING
          date = sy-datum
     IMPORTING
          day  = l_day.
Для даты 16.05.2008 будет возвращен параметр 5.


* Функция возвращает дату представленную во внутреннем формате в нормальный формат, т.е. это обратная конвертация для функции DATE_CONVERT_TO_FACTORYDATE, которая описана выше. Обратите внимание, что поправка на рабочий день выполняется автоматически, т.е. к примеру, если вы укажите число 3995, что равно 01.01.2008, то будет возвращена дата 31.12.2007, т.е. фактически CORRECT_OPTION = '-'. Ну а остальное, вроде, как ясно из текста:
DATA: l_datum LIKE scal-date,
      l_factorydate LIKE scal-facdate.

l_factorydate = '3 996'.
CALL FUNCTION 'FACTORYDATE_CONVERT_TO_DATE'
     EXPORTING
          factorydate                  = l_factorydate
          factory_calendar_id          = 'UA'
     IMPORTING
          date                         = l_date
     EXCEPTIONS
          calendar_buffer_not_loadable = 1
          factorydate_after_range      = 2
          factorydate_before_range     = 3
          factorydate_invalid          = 4
          factory_calendar_id_missing  = 5
          factory_calendar_not_found   = 6
          OTHERS                       = 7.
Результат: 02.01.2008.


Функция позволяющая добавить или отнять месяцы от заданной даты, понимает високосный год.
DATA: l_date LIKE sy-datum.
CALL FUNCTION 'MONTH_PLUS_DETERMINE'
     EXPORTING
          months  = '1'
          olddate = '20080131'
     IMPORTING
          newdate = l_date.
Параметры:
  •     months - количество месяцев которое нужно добавить или отнять от даты. Для вычитания нужно записать значение как -1;
  •     olddate - дата от которой требуется вычесть месяцы;
  •     l_date - новое значение даты.


* Проверяет значение введенной даты на корректность и выдает, строку ошибки, которую можно показать пользователю, что не нравится в веденной им дате:
DATA: l_date LIKE vtb_market-ddate,
      l_sstats LIKE vtb_market-sstats,
      l_error_flg LIKE vtb_market-rupdhist,
      l_error_msg LIKE vtb_market-error.
                                                                        
l_date = '301173'.
CALL FUNCTION 'TB_DATAFEED_CHECK_DATE'
     EXPORTING
          date      = l_date
     CHANGING
          sstats    = l_sstats
          error_flg = l_error_flg
          error_msg = l_error_msg.
В ответ будет получено типа:
  •     l_sstats  = E
  •     l_error_flg = X
  •     l_error_msg = Дата 301173   содержит недопустимый пробел!



* Проверка значения введенной даты. Так сказать еще одна вариация, когда проверяется, что введено. 
function date_check_plausibility.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*"       IMPORTING
*"              DATE LIKE  SY-DATUM
*"       EXCEPTIONS
*"              PLAUSIBILITY_CHECK_FAILED
*"----------------------------------------------------------------------

  data: check_year_1 type p.
  data: check_year_2 type p.

  if date cn '0123456789'.
    message s011 with date raising plausibility_check_failed.
  endif.

  if date+4(2) lt '01'
  or date+4(2) gt '12'.
    message s003 with date+4(2) raising plausibility_check_failed.
  endif.

  if date+6(2) lt '01'
  or date+6(2) gt '31'.
    message s006 with date+6(2) raising plausibility_check_failed.
  endif.

  if date+4(2) eq '01'
  or date+4(2) eq '03'
  or date+4(2) eq '05'
  or date+4(2) eq '07'
  or date+4(2) eq '08'
  or date+4(2) eq '10'
  or date+4(2) eq '12'.
    if date+6(2) gt '31'.
      message s004 with date+6(2) date+4(2)
                   raising plausibility_check_failed.
    endif.
  elseif date+4(2) eq '04'
  or     date+4(2) eq '06'
  or     date+4(2) eq '09'
  or     date+4(2) eq '11'.
    if date+6(2) gt '30'.
      message s004 with date+6(2) date+4(2)
                   raising plausibility_check_failed.
    endif.
  else.
    check_year_1 = date(4) mod 4.      " alle 4 Jahre ist schaltjahr
    if check_year_1 eq 0.
      check_year_1 = date(4) mod 100.  " aber nicht alle 100 Jahre
      check_year_2 = date(4) mod 400.  " aber alle 400 Jahre
      if check_year_1 eq 0
      and check_year_2 ne 0.
        if date+6(2) gt '28'.
          message s004 with date+6(2) date+4(2)
                       raising plausibility_check_failed.
        endif.
      else.
        if date+6(2) gt '29'.
          message s004 with date+6(2) date+4(2)
                       raising plausibility_check_failed.
        endif.
      endif.
    else.
      if date+6(2) gt '28'.
        message s004 with date+6(2) date+4(2)
                     raising plausibility_check_failed.
      endif.
    endif.
  endif.
endfunction.

* Возвращает начальную и конечную дату периода, для заданного варианта финансового года:
DATA: l_fday LIKE bkpf-budat,
      l_lday LIKE bkpf-budat,
      l_speriod LIKE bkpf-bstat.

CALL FUNCTION 'PERIOD_DAY_DETERMINE'
  EXPORTING
    i_gjahr              = '2009'
    i_monat              = '02'
    i_periv              = 'K4'
  IMPORTING
    e_fday               = l_fday
    e_lday               = l_lday
    e_speriod            = l_speriod
  EXCEPTIONS
    error_period         = 1
    error_period_version = 2
    firstday_not_defined = 3
    period_not_defined   = 4
    year_invalid         = 5
    OTHERS               = 6.
На выходе получим:
L_FDAY - 01.02.2009 Дата начала периода
L_LDAY - 28.02.2009 Дата конца периода
L_SPERIOD - SPACE - Признак специального периода проводки

Функция округления даты. В общем виде возвращает последний/первый день недели, месяца, года... иногда полезно, чтобы не вызвать кучу функций расчета даты:
DATA: l_datum LIKE sy-datum.

l_datum = sy-datum.
CALL FUNCTION 'ROUND_DATE'
     EXPORTING
          i_iprkz            = '2'
          i_rdmhd            = '+'
     CHANGING
          c_date             = l_datum
     EXCEPTIONS
          invalid_round_rule = 1
          OTHERS             = 2.
WRITE: / l_datum DD/MM/YYYY.
i_iprkz - код периода. Могут быть следующие значения:
  • SPACE - день, смысла в этом коде нет, так как время не округляется, а возваращаемая дата = переданной дате;
  • '1' = неделя, возвращает дату конца/начала недели;
  • '2' = месяца, возвращает дату конца/начала месяца;
  • '3' = год, возвращает дату конца/начала года.
i_rdmhd - направление округления:
  • '+' - округление до конца периода, т.е. если задан код периода 2, то текущая дата будет округлена до конца периода и будет содержать дату последнего дня месяца.
  • '-' - округление до начала периода, т.е. если задан код периода 2, то текущая дата будет округлена до начала периода и будет содержать дату первого дня месяца. Наверное, это не очень полезно, так как ясно, что дата = 01, а вот началом недели уже не так просто и придется считать.
  • 'F' - округление до конца периода, при этом будет возвращаться следующий день за концом периода, т.е. если выбрано тип '1', то будет возращена дата понедельника следующей недели, тогда как при '+' возвращается дата воскресения.



* Позволяет получить от заданной даты новую дату в будущем, путем добавления месяцев и дней. Про високосный год знает:
DATA: l_result_date LIKE sy-datum.
CALL FUNCTION 'CALCULATE_DATE'
     EXPORTING
          days        = '1'
          months      = '10'
          start_date  = '20080228'
     IMPORTING
          result_date = l_result_date.

WRITE: / l_result_date.
В данном примере возвращает 29.12.2008.


* Возвращает название дня недели по заданной дате, но только на английском языке, по этому примера нет, только наименование:
CALL FUNCTION 'DATE_TO_DAY'
  EXPORTING
    date          =
* IMPORTING
*   WEEKDAY       =.



* Возвращает красивые строчки с расшифровками запрошенных дат, например, 11.02.2008 будут сформированы строки номер дня недели = 3, краткое название дня недели в виде "Ср",  полное название дня "Среда" и название дня недели + дата в виде строки "Среда, 11.Март. 2009", в общем удобно, плюс знает, что это всё может быть написано на разных языках:
DATA: l_date_from LIKE sy-datum,
      l_date_to LIKE sy-datum,
      l_year_of_valid_from LIKE scal-year,
      l_year_of_valid_to LIKE scal-year,
      l_returncode LIKE sy-subrc,
      lt_day_attributes LIKE casdayattr OCCURS 1 WITH HEADER LINE.

l_date_from = sy-datum.
l_date_to = sy-datum + 7.
CALL FUNCTION 'DAY_ATTRIBUTES_GET'
  EXPORTING
*   FACTORY_CALENDAR                 = ' '
*   HOLIDAY_CALENDAR                 = ' '
    date_from                        = l_date_from
    date_to                          = l_date_to
    language                         = sy-langu
  IMPORTING
    year_of_valid_from               = l_year_of_valid_from
    year_of_valid_to                 = l_year_of_valid_to
    returncode                       = l_returncode
  TABLES
    day_attributes                   = lt_day_attributes
  EXCEPTIONS
   factory_calendar_not_found       = 1
   holiday_calendar_not_found       = 2
   date_has_invalid_format          = 3
   date_inconsistency               = 4
   OTHERS                           = 5.

IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
Пример возвращенной таблички:

* Рассчитать количество месяцев между двумя датами. Если i_kz_incl_bis не равно SPACE, тогда к переданной дате i_datum_bis до начала вычислений добавляется один день, что само собой может увеличить/уменьшить количество месяцев на единицу:
DATA: l_datum_bis LIKE sy-datum,
      l_datum_von LIKE sy-datum,
      l_month TYPE i.

l_datum_bis = sy-datum + 100.
l_datum_von = sy-datum.
CALL FUNCTION 'MONTHS_BETWEEN_TWO_DATES'
     EXPORTING
          i_datum_bis   = l_datum_bis
          i_datum_von   = l_datum_von
          i_kz_incl_bis = ' '
     IMPORTING
          e_monate      = l_month.

WRITE: / l_month.
В данном примере l_month = 03.



* Проверяет является переданная дата последним днем месяца + если это високосный год, то второй параметр e_tt будет содержать признак високосной даты в году, параметр e_kz_ult = space дата не последняя дата месяца, "X" - дата является последним днем месяца:
DATA: l_kz_ult(1) TYPE c,
      l_tt TYPE i.

CALL FUNCTION 'END_OF_MONTH_DETERMINE_2'
     EXPORTING
          i_datum  = '20080329'
     IMPORTING
          e_kz_ult = l_kz_ult
          e_tt     = l_tt.



* Расчёт времени в часах и минутах между двумя датами:
DATA: l_date1 LIKE sy-datum,
      l_time1 LIKE sy-uzeit,
      l_date2 LIKE sy-datum,
      l_time2 LIKE sy-uzeit,
      l_tdiff LIKE tvro-fahztd,
      l_date2_early LIKE rv56a-selkz.

l_date1 = sy-datum.
l_time1 = sy-uzeit + 5.
l_date2 = sy-datum + 1.
l_time2 = sy-uzeit + 76.

CALL FUNCTION 'SD_CALC_DURATION_FROM_DATETIME'
     EXPORTING
          i_date1          = l_date1
          i_time1          = l_time1
          i_date2          = l_date2
          i_time2          = l_time2
     IMPORTING
          e_tdiff          = l_tdiff
          e_date2_early    = l_date2_early
     EXCEPTIONS
          invalid_datetime = 1
          OTHERS           = 2.

IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.

WRITE: / l_tdiff,
       / l_date2_early.
Параметр e_date2_early  = Х, если i_date1 > i_date2, иначе равно SPACE. 




* Рассчитывает время между двумя датами в минутах:
DATA: l_date1 LIKE sy-datum,
      l_time1 LIKE sy-uzeit,
      l_date2 LIKE sy-datum,
      l_time2 LIKE sy-uzeit,
      l_delta_time LIKE mcwmit-be_ae,
      l_delta_unit LIKE mcwmit-lzeit.

l_date1 = sy-datum.
l_time1 = sy-uzeit + 5.
l_date2 = sy-datum + 1.
l_time2 = sy-uzeit + 76.

CALL FUNCTION 'L_MC_TIME_DIFFERENCE'
     EXPORTING
          date_from       = l_date1
          date_to         = l_date2
          time_from       = l_time1
          time_to         = l_time2
     IMPORTING
          delta_time      = l_delta_time
          delta_unit      = l_delta_unit
     EXCEPTIONS
          from_greater_to = 1
          OTHERS          = 2.

IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
WRITE: / l_delta_time,
       / l_delta_unit.

* Возвращает не только текущий год, но и месяц. Фактически - текущий открытый период:
DATA: l_currm LIKE bkpf-monat,
      l_curry LIKE bkpf-gjahr,
      l_prevm LIKE bkpf-monat,
      l_prevy LIKE bkpf-gjahr.

CALL FUNCTION 'GET_CURRENT_YEAR'
     EXPORTING
          bukrs = '1000'
          date  = sy-datum
     IMPORTING
          currm = l_currm
          curry = l_curry
          prevm = l_prevm
          prevy = l_prevy.

* Возвращает различное представление даты в формате пользователя. Рекомендуется использовать для формирования строк даты при передаче в батч-интпуты, так как там данные должны быть введены с разделителями пользователя:
DATA: l_mdat4(5) TYPE c,
      l_mdat6(7) TYPE c,
      l_tdat4(5) TYPE c,
      l_tdat6(8) TYPE c,
      l_tdat8(10) TYPE c,
      l_wdat4(5) TYPE c,
      l_wdat6(7) TYPE c.

CALL FUNCTION 'DATUMSAUFBEREITUNG'
 EXPORTING
   flagm                 = 'X'
   flagw                 = 'X'
   idate                 = sy-datum
*   IMONT                 = ' '
*   IWEEK                 = ' '
 IMPORTING
   mdat4                 = l_mdat4
   mdat6                 = l_mdat6
   tdat4                 = l_tdat4
   tdat6                 = l_tdat6
   tdat8                 = l_tdat8
   wdat4                 = l_wdat4
   wdat6                 = l_wdat6
 EXCEPTIONS
   datfm_ungueltig       = 1
   datum_ungueltig       = 2
   OTHERS                = 3.

WRITE: / l_mdat4,
       / l_mdat6,
       / l_tdat4,
       / l_tdat6,
       / l_tdat8,
       / l_wdat4,
       / l_wdat6.
Пример:

* Позволяет к заданной дате добавить требуемое количество месяцев. Помнит про високосный год:
DATA: l_stdate LIKE sy-datum,
      l_count  TYPE i,
      l_eddate LIKE sy-datum.

l_stdate = sy-datum.
l_count = '5'.
CALL FUNCTION 'RE_ADD_MONTH_TO_DATE'
  EXPORTING
    months  = l_count
    olddate = l_stdate
  IMPORTING
    newdate = l_eddate.
WRITE: / 'Начальная дата:', l_stdate,
       / '+', l_count, 'месяцев',
       / 'Конечная дата:', l_eddate.

* Позволяет получить следующее время и дату путем добавления часов, минут и секунд. На вход передаем дату и время, например текущие и время в формате HHMMSS, которое нужно добавить. На выходе получаем новую дату и время:
DATA: l_uzeit LIKE sy-datum,
      l_uzeit LIKE sy-uzeit.

        CALL FUNCTION 'DIMP_ADD_TIME'
          EXPORTING
            iv_starttime = sy-uzeit
            iv_startdate = sy-datum
            iv_addtime   = '000001'
          IMPORTING
            ev_endtime   = l_uzeit
            ev_enddate   = l_erdat.

* Данная функция позволяет получить код/номер периода для заданной даты. В общем виде для варианта финансового года К4, данная задача не является проблемной, номер месяца и есть номер периода, но стандартно в системе могут быть созданы различные варианты финансовых периодов, в банках любят обычно использовать вариант типа 365 периодов в году. Самый простой случай - это работа с кварталом:
DATA: l_period LIKE t009-anzbp,
      l_year LIKE t009b-bdatj.

CALL FUNCTION 'DETERMINE_PERIOD'
  EXPORTING
    date                      = sy-datum
*   PERIOD_IN                 = '00'
    version                   = 'Q1'    "Вариант финансового года (кварталы)
 IMPORTING
   period                    = l_period
   year                      = l_year
 EXCEPTIONS
   period_in_not_valid       = 1
   period_not_assigned       = 2
   version_undefined         = 3
   OTHERS                    = 4.
Переменная PERIOD_IN используется для определения существования особых периодов для варианта финансового года. Правда работает она только в случае если дата задана для последнего возможного периода в варианте года, тогда например для вариант К4, обычно 12 периодов + 4 особых периода, при вызове для любой из дат в диапазоне 01.12 по 31.12 и задании например PERIOD_IN = 18 система будет выдавать ошибку, особый период не существует, если же вызвать с PERIOD_IN = 13, ошибки не будет. 




* Возвращает дату начала и конца квартала, в который входит переданная дата:
DATA: l_start LIKE sy-tabix,
      l_end  LIKE sy-tabix.

CALL FUNCTION 'ISH_QUARTER_GET'
  EXPORTING
    ss_date    = sy-datum
  IMPORTING
    ss_begin   = l_start
    ss_end     = l_end
  EXCEPTIONS
    error      = 1
    wrong_date = 2
    OTHERS     = 3.
Например для даты 15.09.2012 вернет значения:
Begin: 01.07.2012, End: 30.09.2012.


* Возвращает для заданной даты, номер дня в неделе и название дня недели. Название дня в неделе выполняется путем вывода текстовой константы на английском и большими буквами:
DATA: l_day LIKE scal-indicator,
      l_weekday TYPE sc_day_txt.

CALL FUNCTION 'DATE_COMPUTE_DAY_ENHANCED'
  EXPORTING
    date    = sy-datum
  IMPORTING
    day     = l_day
    weekday = l_weekday.

WRITE: / 'Номер дня в неделе:', l_day, 'День недели:', l_weekday.

* Выдает текстовое имя дня недели и полную строку дня. Возвращает таблицу дней, так что можно задать диапазон дат:
Data: l_year_of_valid_from LIKE scal-year,
      l_year_of_valid_to LIKE scal-year,
      l_returncode LIKE sy-subrc,
      l_date_from LIKE scal-date,
      l_date_to LIKE scal-date,
      lt_day_attributes LIKE casdayattr OCCURS 1 WITH HEADER LINE.

l_date_from = '20130101'.
l_date_to = '20130104'.
CALL FUNCTION 'DAY_ATTRIBUTES_GET'
 EXPORTING
*   FACTORY_CALENDAR                 = ' '
*   HOLIDAY_CALENDAR                 = ' '
    date_from                        = l_date_from
    date_to                          = l_date_to
    language                         = sy-langu
    non_iso                          = ' '
 IMPORTING
   year_of_valid_from               = l_year_of_valid_from
   year_of_valid_to                 = l_year_of_valid_to
   returncode                       = l_returncode
  TABLES
    day_attributes                   = lt_day_attributes
 EXCEPTIONS
   factory_calendar_not_found       = 1
   holiday_calendar_not_found       = 2
   date_has_invalid_format          = 3
   date_inconsistency               = 4
   OTHERS                           = 5.

IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
Пример таблицы результата:




* Возвращает кол-во лет, месяцев, дней между 2-мя датами.
Для точности  отнять от даты окончания один день

t_date t_date 1.

  CALL FUNCTION 'HR_HK_DIFF_BT_2_DATES'
    EXPORTING
      date1                   t_date
      date2                   t_dat01
      output_format           '05'
    IMPORTING
      years                   years
      months                  months
      days                    days
    EXCEPTIONS
      invalid_dates_specified 1
      OTHERS                  2.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

2 комментария: