2020 Sep 14 2:50 PM
Hi,
Given a timestamp value, how can we derive it into 30 mins interval so I can assign them into “30 mins block”?
Example 1, timestamp value 20200630000149 so this is actually Date: 30.06.2020, Time: 00:01:49. This will be first 30 mins interval, so the “30 mins block” is 1.
Example 1, timestamp value 20200630003850 so this is actually Date: 30.06.2020, Time: 00:38:50. This will be secon 30 mins interval, so the “30 mins block” is 2.
Any FM can do this?
Thanks in advance.
2020 Sep 15 7:26 AM
The following coding converts any time between 00:00:00 and 23:59:59 into 30-minute blocks, starting with block 1:
" When using the '/' operator for decimal division on a time variable,
" the commercial rounding at half values has to be taken into account
DATA(block) = ( time + CONV t( '001500' ) ) / 1800.
" When using the 'DIV' operator for an integer division on a time variable
" the division result will only be based on the integer part and the remainder will be neglected
" this is what Sandra already posted
DATA(block) = time DIV 1800 + 1
The following report displays different inputs as blocks and block intervals of 30-minutes:
REPORT ztest_time_blocks.
TYPES: BEGIN OF ty_input_s,
timestamp TYPE timestamp,
timezone TYPE timezone,
date TYPE dats,
time TYPE tims,
END OF ty_input_s,
ty_input_t TYPE TABLE OF ty_input_s WITH EMPTY KEY,
BEGIN OF ty_output_s.
INCLUDE TYPE ty_input_s.
TYPES: block TYPE i,
block_from TYPE tims,
block_to TYPE tims,
END OF ty_output_s,
ty_output_t TYPE TABLE OF ty_output_s WITH EMPTY KEY.
" Example Input Data
DATA(input) = VALUE ty_input_t( ( timestamp = '20200630000149' timezone = 'UTC' )
( timestamp = '20200630003850' timezone = 'UTC' )
( timestamp = '20200630103850' timezone = 'UTC' )
( timestamp = '20200630203050' timezone = 'UTC' )
( timestamp = '20200630231850' timezone = 'UTC' ) ).
" Converting Timestamp based on Timezone to Date/Time and vice versa
LOOP AT input ASSIGNING FIELD-SYMBOL(<in>) WHERE timezone IS NOT INITIAL.
IF <in>-timestamp IS NOT INITIAL AND <in>-time IS INITIAL.
CONVERT TIME STAMP <in>-timestamp TIME ZONE <in>-timezone INTO DATE <in>-date TIME <in>-time.
ELSEIF <in>-date IS NOT INITIAL AND <in>-time IS NOT INITIAL AND <in>-timestamp IS INITIAL.
CONVERT DATE <in>-date TIME <in>-time INTO TIME STAMP <in>-timestamp TIME ZONE <in>-timezone.
ENDIF.
ENDLOOP.
" creating block info for output
DATA(output) = VALUE ty_output_t( FOR wa IN input
( timestamp = wa-timestamp
timezone = wa-timezone
date = wa-date
time = wa-time
block = wa-time DIV 1800 + 1
block_from = ( wa-time DIV 1800 ) * 1800
block_to = ( ( wa-time DIV 1800 ) + 1 ) * 1800 - 1 ) ).
* block = ( wa-time + CONV t( '001500' ) ) / 1800
* block_from = ( ( wa-time + CONV t( '001500' ) ) / 1800 - 1 ) * 1800
* block_to = ( ( wa-time + CONV t( '001500' ) ) / 1800 - 1 ) * 1800 + CONV t( '002959' ) ) ).
" Display output
cl_demo_output=>display( output ).

Timestamp vs Date/Time:
Timestamps should in general be based on UTC. Only when displaying timestamp values as date/time values the applicable timezone has to be applied in order to correctly display the date time values.
In your case, you are wanting to create blocks based on 30-minute time intervals for a time value with a specific timezone.
The following input example illustrates this relationship:
" EST M0500 USA X Eastern Time (New York)
" UTC P0000 NONE X UTC+0
" CET P0100 EUROPE X Central Europe
" JAPAN P0900 NONE X Japan
DATA(input) = VALUE ty_input_t( ( timestamp = '20200630000149' timezone = 'EST' )
( timestamp = '20200630000149' timezone = 'UTC' )
( timestamp = '20200630000149' timezone = 'CET' )
( timestamp = '20200630000149' timezone = 'JAPAN' )
( timestamp = '20200630003850' timezone = 'EST' )
( timestamp = '20200630003850' timezone = 'UTC' )
( timestamp = '20200630003850' timezone = 'CET' )
( timestamp = '20200630003850' timezone = 'JAPAN' ) ).

Creating 30 minute blocks
Here is an input example for 60 values in 3 minute steps starting at 23:59:59:
DATA(input) = VALUE ty_input_t( for j = 0 then j + 1 while j < 60
( timestamp = conv timestamp( sy-datum && conv t( j * 180 - 1 ) ) timezone = 'UTC' ) ).

Displaying the block's time intervals
In order to display the time interval for a block, the block value is multiplied by 1'800 seconds for the start of the interval and for the end of the interval the value 29 minutes and 59 seconds is added.
The following input example displays all 48 blocks and the corresponding intervals:
DATA(input) = VALUE ty_input_t( for j = 0 then j + 1 while j < 48
( timestamp = conv timestamp( sy-datum && conv t( j * 1800 ) ) timezone = 'UTC' ) ).

2020 Sep 14 2:58 PM
result = cond #( when char_timestamp+10(2) lt '30' then '1' else '2' ).something like that ?
2020 Sep 14 3:04 PM
Hello fujibau
Get the separate date and time values first with the CONVERT TIME STAMP keyword: https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-us/abapconvert_time-stamp.htm
Then, from time variable.
DATA:
lv_hours TYPE i,
lv_minutes TYPE i,
lv_segment TYPE i.
lv_hours = lv_time+0(2).
lv_minutes = lv_time+2(2).
lv_hours = lv_hours + 1.
lv_segment = lv_hours * 2.
IF lv_minutes < 30.
lv_segment = lv_segment - 1.
ENDIF.Kind regards,2020 Sep 14 3:55 PM
Why a function module if ABAP is much shorter?
Remember that if you convert a type T variable into I (integer), SAP converts the time into seconds.
DATA(block) = CONV t( char_timestamp+8(6) ) DIV 1800 + 1. " 1800 seconds = 30 minutes
Examples:
DATA: char_timestamp TYPE c LENGTH 14,
block TYPE i.
char_timestamp = '2020063000149'.
block = CONV t( char_timestamp+8(6) ) DIV 1800 + 1.
ASSERT block = 1.
char_timestamp = '20200630003850'.
block = CONV t( char_timestamp+8(6) ) DIV 1800 + 1.
ASSERT block = 2.EDIT: be carefult concerning the Time Zone in which the time is expressed, 11am in France (9 or 10am UTC) is not the same 11am in South Korea (~2am UTC). UTC is the same time for anyone in the Universe/World, now is 9:39am for everyone in the world. If you want a "UTC block number" you have to convert your time to UTC, and you first have to know in what time zone is expressed your time. For more information, see Michael P. answer and comment.
2020 Sep 15 9:52 AM
sandra.rossi, I totally agree with the calculation part of your solution which creates the half-hour blocks based on a time field. And based on the specifics of the OP's question, you are providing the basic coding how the conversion of the timestamp into a time field could be done.
In general, timestamps should always be handled in UTC.
Only when displaying timestamp values as date/time values, the applicable timezone has to be applied in order to correctly display the date time values.
I believe the OP needs to be made aware of the possible shortsightedness of the presented requirements.
2020 Sep 15 10:52 AM
michael.piesche Well, you have the right approach in explaining all these things to people, but it takes a lot of time (bravo to you), and people often just don't want to spend more time on their initial question.
What I did is to edit my answer and refer to your question.
Note that the problem is much more complex, because maybe the OP situation is to calculate a "local" block number. For example the block number used to know how many parcels are delivered in the world in the morning rather than in the afternoon (morning and afternoon have a "local" meaning). A "UTC block number" (or whatever time zone is chosen as a reference) has an interest only if you want something like know the number of people using an internet website by block of 30 minutes.
2020 Sep 14 11:57 PM
Hi All,
Many thanks for your input.
It is not only following 2 timestamp, it can be anytime timestamp during a day (24 hours).
timestamp value 20200630000149
timestamp value 20200630003850
Example:
timestamp value 20200630103850
timestamp value 20200630203050
timestamp value 20200630111850
Any help is much apprecaited.
2020 Sep 15 7:47 AM
This is what Sandra's logic provides. Just use it with different timestamps and you will get different block numbers.
Kind regards,2020 Sep 15 8:01 AM
Please use button COMMENT if you don't propose a solution. The button ANSWER is reserved to proposing a solution.
2020 Sep 15 7:26 AM
The following coding converts any time between 00:00:00 and 23:59:59 into 30-minute blocks, starting with block 1:
" When using the '/' operator for decimal division on a time variable,
" the commercial rounding at half values has to be taken into account
DATA(block) = ( time + CONV t( '001500' ) ) / 1800.
" When using the 'DIV' operator for an integer division on a time variable
" the division result will only be based on the integer part and the remainder will be neglected
" this is what Sandra already posted
DATA(block) = time DIV 1800 + 1
The following report displays different inputs as blocks and block intervals of 30-minutes:
REPORT ztest_time_blocks.
TYPES: BEGIN OF ty_input_s,
timestamp TYPE timestamp,
timezone TYPE timezone,
date TYPE dats,
time TYPE tims,
END OF ty_input_s,
ty_input_t TYPE TABLE OF ty_input_s WITH EMPTY KEY,
BEGIN OF ty_output_s.
INCLUDE TYPE ty_input_s.
TYPES: block TYPE i,
block_from TYPE tims,
block_to TYPE tims,
END OF ty_output_s,
ty_output_t TYPE TABLE OF ty_output_s WITH EMPTY KEY.
" Example Input Data
DATA(input) = VALUE ty_input_t( ( timestamp = '20200630000149' timezone = 'UTC' )
( timestamp = '20200630003850' timezone = 'UTC' )
( timestamp = '20200630103850' timezone = 'UTC' )
( timestamp = '20200630203050' timezone = 'UTC' )
( timestamp = '20200630231850' timezone = 'UTC' ) ).
" Converting Timestamp based on Timezone to Date/Time and vice versa
LOOP AT input ASSIGNING FIELD-SYMBOL(<in>) WHERE timezone IS NOT INITIAL.
IF <in>-timestamp IS NOT INITIAL AND <in>-time IS INITIAL.
CONVERT TIME STAMP <in>-timestamp TIME ZONE <in>-timezone INTO DATE <in>-date TIME <in>-time.
ELSEIF <in>-date IS NOT INITIAL AND <in>-time IS NOT INITIAL AND <in>-timestamp IS INITIAL.
CONVERT DATE <in>-date TIME <in>-time INTO TIME STAMP <in>-timestamp TIME ZONE <in>-timezone.
ENDIF.
ENDLOOP.
" creating block info for output
DATA(output) = VALUE ty_output_t( FOR wa IN input
( timestamp = wa-timestamp
timezone = wa-timezone
date = wa-date
time = wa-time
block = wa-time DIV 1800 + 1
block_from = ( wa-time DIV 1800 ) * 1800
block_to = ( ( wa-time DIV 1800 ) + 1 ) * 1800 - 1 ) ).
* block = ( wa-time + CONV t( '001500' ) ) / 1800
* block_from = ( ( wa-time + CONV t( '001500' ) ) / 1800 - 1 ) * 1800
* block_to = ( ( wa-time + CONV t( '001500' ) ) / 1800 - 1 ) * 1800 + CONV t( '002959' ) ) ).
" Display output
cl_demo_output=>display( output ).

Timestamp vs Date/Time:
Timestamps should in general be based on UTC. Only when displaying timestamp values as date/time values the applicable timezone has to be applied in order to correctly display the date time values.
In your case, you are wanting to create blocks based on 30-minute time intervals for a time value with a specific timezone.
The following input example illustrates this relationship:
" EST M0500 USA X Eastern Time (New York)
" UTC P0000 NONE X UTC+0
" CET P0100 EUROPE X Central Europe
" JAPAN P0900 NONE X Japan
DATA(input) = VALUE ty_input_t( ( timestamp = '20200630000149' timezone = 'EST' )
( timestamp = '20200630000149' timezone = 'UTC' )
( timestamp = '20200630000149' timezone = 'CET' )
( timestamp = '20200630000149' timezone = 'JAPAN' )
( timestamp = '20200630003850' timezone = 'EST' )
( timestamp = '20200630003850' timezone = 'UTC' )
( timestamp = '20200630003850' timezone = 'CET' )
( timestamp = '20200630003850' timezone = 'JAPAN' ) ).

Creating 30 minute blocks
Here is an input example for 60 values in 3 minute steps starting at 23:59:59:
DATA(input) = VALUE ty_input_t( for j = 0 then j + 1 while j < 60
( timestamp = conv timestamp( sy-datum && conv t( j * 180 - 1 ) ) timezone = 'UTC' ) ).

Displaying the block's time intervals
In order to display the time interval for a block, the block value is multiplied by 1'800 seconds for the start of the interval and for the end of the interval the value 29 minutes and 59 seconds is added.
The following input example displays all 48 blocks and the corresponding intervals:
DATA(input) = VALUE ty_input_t( for j = 0 then j + 1 while j < 48
( timestamp = conv timestamp( sy-datum && conv t( j * 1800 ) ) timezone = 'UTC' ) ).

2020 Sep 15 2:20 PM
Thanks michael.piesche.
In that case, if I want to create 15 mins block instead of 30 mins, can I divide by 900 instead of 1800
example:
block = wa-time DIV 900 + 1
2020 Sep 15 2:29 PM
yes 😉
" 24 hours have 24*60*60 seconds
" - if you divide 24 hours by 3'600 seconds, you get 24 blocks with 60 minute time intervals (hours)
" - if you divide 24 hours by 1'800 seconds, you get 48 blocks with 30 minute time intervals (half-hours)
" - if you divide 24 hours by 900 seconds, you get 96 blocks with 15 minute time intervals (quarter-hours)
2020 Oct 05 1:48 AM
Hi,
Can you explain again why must we have "+ 1" in the following formula:
block= wa-time DIV 900 + 1
Thanks