为什么在添加夏令时时 CONVERT DATE 会因 sy-subrc 12 而失败?
Why does CONVERT DATE fail with sy-subrc 12 when adding DAYLIGHT SAVING TIME?
以下代码失败 sy-subrc=12
。
CONVERT DATE '20191105'
TIME '123000'
DAYLIGHT SAVING TIME 'X'
INTO TIME STAMP DATA(timestamp)
TIME ZONE 'CET '.
在 ABAP documentation 中说:
12 : The specified time could not be converted, because dat, tim, or dst contain invalid or inconsistent values.
我注意到,当我在调试器的 sy-dayst 中删除 'X' 时,它会进行转换。
但是我当然想考虑夏令时,那么我怎样才能做到这一点呢?
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:是的,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 时间或本地时间(这甚至不是唯一的如果是夏令时!)
TL;DR
Never use DAYLIGHT SAVING TIME
(except in very special cases if you're expert)
@konstantin 说得好:
"CONVERT DATE command automatically takes care of DST"
解释:
DAYLIGHT SAVING TIME 'X'
仅当本地时间(DATE 和 TIME)与从夏令时到冬令时的一小时(很少是两小时)间隔匹配时才能使用,对于给定的时区(注意一些时区没有夏令时)。
例如,2003年,巴西在3月9日(星期日)凌晨2点切换到冬令时;凌晨 2 点,时钟必须拨回一小时至凌晨 1 点,因此 1:30am 出现了两次。
因此,如果 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'
是否必须使用。事实上,如果数据库 table 包含我在上面的示例中使用的本地时间, 就无法知道 是夏令时还是冬令时,因为夏令时是从未分配给 table 列以及日期和时间列。
这就是为什么 SAP 在大约 10 年前推出了一个解决方案,这使得 DAYLIGHT SAVING TIME
几乎过时了。实际问题不是夏令时,而是可能导致时间排序等问题的非连续时间。解决方案的原理是在夏令时切换时放慢时间,使一个给定的时间不会出现两次,时间保持连续。从技术上讲,它会影响系统变量 SY-DATUM
(日期)和 SY-UZEIT
(时间)。在这个 "double hour" 间隔中,需要两秒才能成为一个 SAP 秒。此行为通过配置文件参数 zdate/DSTswitch_contloctime
默认激活(值 "on"),您可以通过事务代码 RZ11
查看该参数。下面是根据旧的("off")或新的方式("on")的 SAP 时间,如果切换发生在当地时间凌晨 2 点(使用 "on",则看不到切换):
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 TIME
,CONVERT
将分别给出这些UTC时间戳,03:59:59和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/ and SAP note 950114 - Profile parameter zdate/DSTswitch_contloctime.
注意SY-DAYST
对应应用服务器当前时间的夏令时指标(SY-DATUM
,SY-UZEIT
,时区定义在tableTTZCU
).我没有看到任何可能的用法。如果你想把最初用SY-DATUM
和SY-UZEIT
获得的时间转换成UTC时间戳,你应该使用classCL_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 所展示的(DATE '20190331' TIME '023000' [...] 德国不存在当地时间),CONVERT DATE
没有DAYLIGHT SAVING TIME
可能 return sy-subrc=12
在极少数情况下,如果输入的日期和时间对应于 "vanishing hour" 内的某些内容,由于从冬令时切换到夏令时 if 时间区域有夏令时。例如:"at 2am, it is 3am",当地时间“2:30am”根本不存在。
以下代码失败 sy-subrc=12
。
CONVERT DATE '20191105'
TIME '123000'
DAYLIGHT SAVING TIME 'X'
INTO TIME STAMP DATA(timestamp)
TIME ZONE 'CET '.
在 ABAP documentation 中说:
12 : The specified time could not be converted, because dat, tim, or dst contain invalid or inconsistent values.
我注意到,当我在调试器的 sy-dayst 中删除 'X' 时,它会进行转换。
但是我当然想考虑夏令时,那么我怎样才能做到这一点呢?
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:是的,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 时间或本地时间(这甚至不是唯一的如果是夏令时!)
TL;DR
Never use
DAYLIGHT SAVING TIME
(except in very special cases if you're expert)
@konstantin 说得好:
"CONVERT DATE command automatically takes care of DST"
解释:
DAYLIGHT SAVING TIME 'X'
仅当本地时间(DATE 和 TIME)与从夏令时到冬令时的一小时(很少是两小时)间隔匹配时才能使用,对于给定的时区(注意一些时区没有夏令时)。
例如,2003年,巴西在3月9日(星期日)凌晨2点切换到冬令时;凌晨 2 点,时钟必须拨回一小时至凌晨 1 点,因此 1:30am 出现了两次。
因此,如果 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'
是否必须使用。事实上,如果数据库 table 包含我在上面的示例中使用的本地时间, 就无法知道 是夏令时还是冬令时,因为夏令时是从未分配给 table 列以及日期和时间列。
这就是为什么 SAP 在大约 10 年前推出了一个解决方案,这使得 DAYLIGHT SAVING TIME
几乎过时了。实际问题不是夏令时,而是可能导致时间排序等问题的非连续时间。解决方案的原理是在夏令时切换时放慢时间,使一个给定的时间不会出现两次,时间保持连续。从技术上讲,它会影响系统变量 SY-DATUM
(日期)和 SY-UZEIT
(时间)。在这个 "double hour" 间隔中,需要两秒才能成为一个 SAP 秒。此行为通过配置文件参数 zdate/DSTswitch_contloctime
默认激活(值 "on"),您可以通过事务代码 RZ11
查看该参数。下面是根据旧的("off")或新的方式("on")的 SAP 时间,如果切换发生在当地时间凌晨 2 点(使用 "on",则看不到切换):
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 TIME
,CONVERT
将分别给出这些UTC时间戳,03:59:59和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/ and SAP note 950114 - Profile parameter zdate/DSTswitch_contloctime.
注意SY-DAYST
对应应用服务器当前时间的夏令时指标(SY-DATUM
,SY-UZEIT
,时区定义在tableTTZCU
).我没有看到任何可能的用法。如果你想把最初用SY-DATUM
和SY-UZEIT
获得的时间转换成UTC时间戳,你应该使用classCL_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 所展示的(DATE '20190331' TIME '023000' [...] 德国不存在当地时间),CONVERT DATE
没有DAYLIGHT SAVING TIME
可能 return sy-subrc=12
在极少数情况下,如果输入的日期和时间对应于 "vanishing hour" 内的某些内容,由于从冬令时切换到夏令时 if 时间区域有夏令时。例如:"at 2am, it is 3am",当地时间“2:30am”根本不存在。