The following code fails with sy-subrc=12
.
CONVERT DATE '20191105'
TIME '123000'
DAYLIGHT SAVING TIME 'X'
INTO TIME STAMP DATA(timestamp)
TIME ZONE 'CET '.
In the ABAP documentation it says:
12 : The specified time could not be converted, because dat, tim, or dst contain invalid or inconsistent values.
I noticed that when I remove the 'X' in sy-dayst in the debugger it does the conversion.
But of course I want to take daylight savings into consideration so how can I make this work?
TL;DR
Never use
DAYLIGHT SAVING TIME
(except in very special cases if you're expert)
And well said by @konstantin :
"CONVERT DATE command automatically takes care of DST"
Explanation:
DAYLIGHT SAVING TIME 'X'
can be used only if the local time (DATE and TIME) matches the one-hour (rarely two hours) interval to switch from summer time to winter time, for the given time zone (note that some time zones have no daylight saving time).
For instance, in 2003, Brazil switched to the winter time on March 9th (Sunday) at 2am; at 2am, the clocks had to be moved back one hour to 1am, and consequently 1:30am occured twice.
So, if ABAP has to convert the local time 2003/03/09 01:30:00 to the UTC time, it has to know if the local time is during the daylight saving time (winter time) or not (summer time), which respectively correspond to the UTC times 2003/03/09 03:30:00 or 2003/03/09 04:30:00.
Demonstration:
DATA: time_stamp TYPE timestamp,
dat TYPE d,
tim TYPE t,
tz TYPE ttzz-tzone.
tz = 'BRAZIL'. "UTC-03:00
dat = '20030309'.
tim = '013000'.
CONVERT DATE dat TIME tim DAYLIGHT SAVING TIME 'X' " winter time
INTO TIME STAMP time_stamp TIME ZONE tz.
ASSERT time_stamp = '20030309033000'. " UTC time
CONVERT DATE dat TIME tim DAYLIGHT SAVING TIME ' ' " summer time
INTO TIME STAMP time_stamp TIME ZONE tz.
ASSERT time_stamp = '20030309043000'. " UTC time
Now, the question is, how to know whether DAYLIGHT SAVING TIME 'X'
has to be used or not. In fact, if a database table contains the local time I used in the example above, one can't know whether it's summer time or winter time because the daylight saving time is never assigned to a table column along with the date and time columns.
That's why SAP has introduced a solution, ~10 years ago, which made DAYLIGHT SAVING TIME
almost obsolete. The actual problem was not the daylight saving time but the non-continuous time which could lead to issues like chronological sorting. The principle of the solution is to slow down the time during the daylight saving time switch, so that one given time never occurs twice and the time remains continuous. Technically, it affects the system variables SY-DATUM
(date) and SY-UZEIT
(time). In this "double hour" interval, two real seconds are needed to make one SAP second. This behavior is activated by default (value "on") via the profile parameter zdate/DSTswitch_contloctime
which you may view via the transaction code RZ11
. Below is the SAP time according to the old ("off") or new way ("on"), if the switch occurs at local time 2am (with "on", you don't see the switch):
off: 1:00, 1:30, 1:00, 1:30, 2:00
on : 1:00, 1:15, 1:30, 1:45, 2:00
Just to add complexity, note that CONVERT
still have a one-hour gap. For example, with zdate/DSTswitch_contloctime
set to "on" and without DAYLIGHT SAVING TIME
, CONVERT
will give these UTC timestamps respectively, there is a gap of one hour between 03:59:59 and 05:00:00:
3:00, 3:15, 3:30, 3:45, 5:00
But this gap is not a big drawback, compared to the risk of having chronological sort issues.
More information: https://blogs.sap.com/2009/12/09/daylight-saving-time-and-slowing-down-the-time/ and SAP note 950114 - Profile parameter zdate/DSTswitch_contloctime.
Note that SY-DAYST
corresponds to the DST indicator of the current time of the application server (SY-DATUM
, SY-UZEIT
, and time zone being defined in table TTZCU
). I don't see any possible usage of it. If you want to convert a time which was initially obtained with SY-DATUM
and SY-UZEIT
, into a UTC time stamp, you should use the method SYSTEMTSTMP_SYST2UTC
of class CL_ABAP_TSTMP
. Example to get the current time:
cl_abap_tstmp=>systemtstmp_syst2utc(
EXPORTING
syst_date = sy-datum
syst_time = sy-uzeit
IMPORTING
utc_tstmp = DATA(now_utc) ).
As @konstantin demonstrated ("DATE '20190331' TIME '023000' [...] local time does not exist in germany"), CONVERT DATE
without DAYLIGHT SAVING TIME
may return sy-subrc=12
in rare occasions, if the input date and time correspond to something inside the "vanishing hour" due to the switch from winter time to summer time the if the time zone has DST. For instance: "at 2am, it is 3am", the local time "2:30am" doesn't exist at all.
So you mean I don't need to pass DAYLIGHT SAVING TIME because CET will cause the Date to convert the correct way already?
tl;dr: Yes, the CONVERT DATE
command automatically takes care of DST (at least for timezone CET
). The sy-subrc==12
ist set for illegal arguments.
Here's a minimal program for your snippet that covers all the edge cases. I added the resulting timestamps in a readable format (manually edited) in the comments.
CONVERT DATE '20190101' TIME '000000' "" // german 'winter time' (no DST, GMT+1)
INTO TIME STAMP DATA(timestamp0) "" // 2018-12-31T23:00:00Z
TIME ZONE 'CET '.
CONVERT DATE '20190701' TIME '000000' "" // german 'summer time' (DST, GMT+2)
INTO TIME STAMP DATA(timestamp1) "" // 2019-06-30T22:00:00Z
TIME ZONE 'CET '.
CONVERT DATE '20190331' TIME '015959' "" // last second before non DST (GMT+1) ==> DST (GMT+2) transition
INTO TIME STAMP DATA(timestamp2) "" // 2019-03-31T00:59:59
TIME ZONE 'CET '.
CONVERT DATE '20190331' TIME '023000' "" // local time does not exist in germany, it's skipped
INTO TIME STAMP DATA(timestamp3) "" // '0' <-- is this initial?
TIME ZONE 'CET '.
""// sy-subrc == 12 here!
CONVERT DATE '20190331' TIME '030000' "" // first second of german DST (GMT+2)
INTO TIME STAMP DATA(timestamp4) "" // 2019-03-31T01:00:00Z
TIME ZONE 'CET '.
CONVERT DATE '20191027' TIME '015959' "" // last second before SAP undefined time range (turn your system off now)
INTO TIME STAMP DATA(timestamp5) ""// 2019-10-26T23:59:59Z
TIME ZONE 'CET '.
CONVERT DATE '20191027' TIME '023000' "" // in the undefined zone, could theoretically be both DST and non-DST
INTO TIME STAMP DATA(timestamp6) "" 2019-10-27T00:30:00Z <-- but is treated as DST
TIME ZONE 'CET '.
CONVERT DATE '20191027' TIME '030000' "" // first second in non DST time (german winter, GMT+1 again)
INTO TIME STAMP DATA(timestamp7) "" 2019-10-27T02:00:01Z
TIME ZONE 'CET '.
There a reason why modern programming languages handle datetime objects as something more complex than just 8 or 14 numeric character long strings. Dealing with different timezones and local vs. UTC data is annoying in ABAP because most of the SAP tables and dependent function modules and classes randomly assume that stored dates and times are either in UTC or local time (which is not even unique in case of DST!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With