Simple(?) task: look at the past 24 hours
Often, a seemingly small and simple task is actually a little bigger, the more and deeper you think of it, you sure have experienced this as well. Here’s an example:
Task: Select something from the last 24 hours (e.g. sales orders (VBAK) maybe to see the turnover in $ in the last 24h hours, or how many units of Product X have been produced per plant )
So, we need to calculate the “target” date and time -> 24 hours in the past.
1.st approach:
data(lv_target_date) = sy-datum - 1.
data(lv_target_time) = sy-uzeit.
simple.
But we probably want 24hours back from the users “definition of now“, not from the system-time (yeah, they might be different, if user and server are in different timezones), so better use sy-datlo + sy-timlo:
data(lv_target_date) = sy-datlo - 1.
data(lv_target_time) = sy-timlo.
Now the following was not explicitly stated, but implicitly it is: If “today” is a Monday, we would want to look back as far as Friday (’cause there’s not turnover/production/… at the weekend – well, unless we have online sales, but that’s another story.)
So, things are clear: we have to take the factory calendar into account.
SELECT SINGLE fabkl FROM t001w INTO data(lv_factory_calendar)
WHERE werks = iv_werks.
*if there is no factory calendar, we're fine with what we already calculated!
CHECK sy-subrc EQ 0.
CHECK lv_factory_calendar IS NOT INITIAL.
CALL FUNCTION 'DATE_CONVERT_TO_FACTORYDATE'
EXPORTING
correct_option = '-'
date = lv_target_date
factory_calendar_id = lv_factory_calendar
IMPORTING
date = lv_target_date
* factorydate =
* 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.
IF sy-subrc <> 0.
*doesn't matter.
ENDIF.
What does it do: if what we calculated as lv_target_day in the first step is NOT a working day, go as far back, until you hit a working day.
That’s what I wanted to say about the date part, but I also have one for the time:
If it’s March, 28th (this year, 2018), 8 O’clock in the morning, what’s the target if we go 24h back? Well: March, 27th, 7 O’clock in the morning! That’s right, at least if we are in a timezone which switched to daylight-saving-time: the hour between 2 and 3 didn’t exist that night!
I have no solution to that, I think this can or at least should not be coded by hand. I would hope + guess that there’s a library somewhere, which takes care of exactly those things I mentioned here. If you know it, please share in the comments.
Let me end with a nice blog I read a few years ago and now went searching for again:
http://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time
( If you like it, you probably like this one about names as well:
https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/ )
Also, to link to a currently trending topic: you probably can and should write #unit-tests for those edge-cases displayed here.
Over to you:
– Do you see other problems not yet addressed here?
– Do you know the library (e.g. ABAP-Class) that helps me with all the time-handling
– I guess there should be a more modern way (ABAP-Class) for “CALL FUNCTION ‘DATE_CONVERT_TO_FACTORYDATE'” , do you know it?
– would you have fallen for one of the ‘traps’ I mentioned here, where they all obvious to you?
This and other input is most welcome!
best
Joachim
That's the kind of blog post I like! Well written, about a problem most developers encounter at some point. Co-incidentally my last post was also about dealing with time/date data so I can relate to this one.
Thanks for your feedback, Lars!
I'll take the opportunity to have a look at the blog you mentioned. 🙂
To subtract 24h from March, 28th (this year, 2018), 8 O’clock in the morning, you should convert the initial date/time from its time zone to UTC, subtract 24h, then convert back from UTC to the initial time zone. UTC never varies (except from time to time to adjust to the actual position of the Earth around the sun...)
Hi Joachim,
Adding my 2 cents to what Sandra Rossi has already mentioned:
You can refer to the code snippet below to see my approach to your problem:
BR,
Suhas
Thank you Suhas. Yep, I forgot to mention CL_ABAP_TSTMP 😉
One point I didn't follow:
Why would you like to use user time (sy-timlo) instead of system time (sy-uzeit)?
As far as I know, unless code is written wrongly, all DB values of dates/times should be written in system time. Hence, selection by user time would lead to incorrect reults.
A valid point!
If i understand correctly the data correctness depends on the discipline of the developer.
Sometimes i wonder why isn't "time" (timestamp, as well) handled as currency/quantity field in ABAP? IMHO 09:00 alone without the timezone isn't a complete representation of time! After all time is relative 😉
Any thoughts?
Well, at least in case of timestamps, time zone is quite redundant because value should always be in UTC (again, unless code is bad).
Thanks Sandra Rossi and Suhas Saha for the general idea and the implementation example with timestamps.
Very clever, I'll add this to my coding best practices!
So far, no one has mentioned an alternative for
and I also see Suhas using it in the example, so it's probably the best we currently have, right?!
best
Joachim
Well, DATE_CONVERT_TO_FACTORYDATE will do the work, but you can also use FM END_TIME_DETERMINE.
No modern way, AFAIK