为什么在添加DAYLIGHT SAVING TIME时,用sy subrc 12转换日期失败



以下代码使用sy-subrc=12失败。

CONVERT DATE '20191105'
TIME '123000'
DAYLIGHT SAVING TIME 'X'
INTO TIME STAMP DATA(timestamp)
TIME ZONE 'CET   '.

在ABAP文件中,它说:

12:无法转换指定的时间,因为dat、tim或dst包含无效或不一致的值。

我注意到,当我在调试器中删除sy-dayst中的"X"时,它会进行转换。

但我当然想考虑夏令时,那么我该如何做到这一点呢?

TL;博士

永远不要使用DAYLIGHT SAVING TIME(除非在非常特殊的情况下,如果你是专家)

@konstantin说得很好:

"CONVERT DATE命令自动处理DST">

解释:

对于给定的时区,只有当本地时间(DATE和time)与从夏季时间切换到冬季时间的一小时(很少是两小时)间隔匹配时,才能使用DAYLIGHT SAVING TIME 'X'(请注意,有些时区没有夏令时)。

例如,2003年,巴西在3月9日(周日)凌晨2点改为冬季;凌晨2点,时钟不得不向后移动一个小时到凌晨1点,因此凌晨1点30分出现了两次。

因此,如果ABAP必须将当地时间2003/03/09 01:30:00转换为UTC时间,它必须知道当地时间是在夏令时(冬季时间)还是不是(夏季时间),分别对应于UTC时间2003/03/0903:30:00或2003/03/0904:30:00。

演示:

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

现在的问题是,如何知道是否必须使用DAYLIGHT SAVING TIME 'X'。事实上,如果数据库表包含我在上例中使用的本地时间,就不知道是夏时制还是冬时制,因为夏令时从未与日期和时间列一起分配给表列。


这就是为什么SAP在大约10年前推出了一种解决方案,使DAYLIGHT SAVING TIME几乎过时。实际的问题不是夏令时,而是非连续时间,这可能会导致时间排序等问题。解决方案的原理是在夏令时切换期间放慢时间,这样一个给定的时间就不会出现两次,并且时间保持连续。从技术上讲,它影响系统变量SY-DATUM(日期)和SY-UZEIT(时间)。在这个"两小时"的时间间隔中,一个SAP秒需要两秒。此行为在默认情况下通过配置文件参数zdate/DSTswitch_contloctime激活(值"on"),您可以通过事务代码RZ11查看该配置文件参数。以下是根据旧的("关闭")或新的方式("打开")的SAP时间,如果切换发生在当地时间凌晨2点(带有"打开",则您看不到切换):

off: 1:00, 1:30, 1:00, 1:30, 2:00
on : 1:00, 1:15, 1:30, 1:45, 2:00

为了增加复杂性,请注意CONVERT仍有一个小时的间隔。例如,如果zdate/DSTswitch_contloctime设置为"on",而没有DAYLIGHT SAVING TIMECONVERT将分别给出这些UTC时间戳,03:59:59和05:00:00:之间有一个小时的间隔

3:00, 3:15, 3:30, 3:45, 5:00

但与存在时间排序问题的风险相比,这种差距并不是一个大缺点。

更多信息:https://blogs.sap.com/2009/12/09/daylight-saving-time-and-slowing-down-the-time/SAP注释950114-配置文件参数zdate/DSTswitch_contloctime。


注意,SY-DAYST对应于应用服务器的当前时间的DST指示符(SY-DATUMSY-UZEIT和时区在表TTZCU中定义)。我看不出它有任何可能的用法。如果你想将最初用SY-DATUMSY-UZEIT获得的时间转换为UTC时间戳,你应该使用类CL_ABAP_TSTMP的方法SYSTEMTSTMP_SYST2UTC。获取当前时间的示例:

cl_abap_tstmp=>systemtstmp_syst2utc(
EXPORTING
syst_date = sy-datum
syst_time = sy-uzeit
IMPORTING
utc_tstmp = DATA(now_utc) ).

正如@konstantin所证明的("德国不存在日期'20190331'时间'023000'[…]当地时间"),如果输入的日期和时间对应于"消失小时"内的某个时间,则在极少数情况下,如果时区具有夏令时,则没有DAYLIGHT SAVING TIMECONVERT DATE可能会返回sy-subrc=12。例如:"凌晨2点,现在是凌晨3点",当地时间"凌晨2:30"根本不存在。

所以你的意思是我不需要通过DAYLIGHT节省时间,因为CET会导致日期已经以正确的方式转换?

tl;dr:是的,CONVERT DATE命令会自动处理DST(至少对于时区CET)。为非法参数设置了sy-subrc==12

这里有一个针对您的代码片段的最小程序,它涵盖了所有的边缘情况。我在评论中添加了可读格式(手动编辑)的时间戳。

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   '.

现代编程语言将日期时间对象处理为比8或14个数字字符长的字符串更复杂的对象是有原因的。在ABAP中,处理不同的时区和本地与UTC的数据是令人讨厌的,因为大多数SAP表和相关功能模块和类都随机假设存储的日期和时间是UTC或本地时间(在DST的情况下,这甚至不是唯一的!)

相关内容

最新更新