Skip to Content

In a first blog post regarding conversions in SAP Gateway Foundation we discussed their relevance in the context of the differences between the ABAP type system and the OData type system. Although not directly related to conversions the handling of date and time perfectly fits into this topic.

ABAP knows date, time, and different representations of time stamps. And, it provides reuse functions to execute date and time calculations. OData has its own date and time definitions with functions that may be used in $filter expressions, for example.

Often, questions arise how the different representations map and how a data provider needs to be implemented to create a best match between both worlds. It is certainly not possible to dig into each and every detail. But, let us start with a few aspects.

Date and Time in OData

To represent date and time information, the OData specification in version 2.0 knows the three primitive types

  • Edm.DateTime,
  • Edm.Time, and
  • Edm.DateTimeOffset.

Since this is not really sufficient for business applications specification version 4.0 switches to

  • Edm.Date,
  • Edm.TimeOfDay,
  • Edm.DateTimeOffset, and
  • Edm.Duration.

We focus on specification version 2.0 and restrict the discussion to Edm.DateTime and Edm.DateTimeOffset. Details regarding the representations can be found in the OData specification, the ISO 8601 standard, and in http://www.w3.org/TR/xmlschema-2. Here, we quickly list the different formats. The literals are used in the URI, that is, in $filter expressions or key predicates, for example. ATOM and JSON refer to the content type of the request or response payload. The number of decimal places available for sub-seconds is defined by the facet precision.

Edm.DateTime represents a date and a time in UTC (formerly, Greenwich Mean Time):

Representation Example
Literal datetime’yyyy-mm-ddThh:mm[:ss[.fffffff]]’ datetime’2016-07-08T12:34:56′
ATOM yyyy-mm-ddThh:mm[:ss[.fffffff]] 2016-07-08T12:34:56
JSON “\/Date(<ticks>)\/”<ticks> = number of milliseconds since midnight Jan 1, 1970 “\/Date(1467981296000)\/”

The ticks in the JSON representation may also be negative to describe dates and time before Jan 1, 1970. “\/Date(-6847804800000)\/” is midnight Jan 1, 1753, for example.

Edm.DateTimeOffset adds time zone information relative to UTC. The date and time information is amended by the standard time difference (offset) with the sign v: +01:00 for Central European Time (CET) or -05:00 for Eastern Standard Time (EST), for example.

Representation Example
Literal datetimeoffset’yyyy-mm-ddThh:mm:ss[.fffffff]Z|vii:nn’ datetimeoffset’1970-01-01T00:00:01+01:00′
ATOM yyyy-mm-ddThh:mm:ss[.fffffff]Z|vii:nn 1970-01-01T00:00:01+01:00
JSON “\/Date(<ticks>[“+” | “-” <offset>)\/”<ticks> = number of milliseconds since midnight Jan 1, 1970<offset> = number of minutes to add or subtract “\/Date(1000+0060)\/”

The character Z at the end of the literal or ATOM representation refers to UTC. Hence, datetimeoffset’2016-07-08T12:34:56Z’ and datetime’2016-07-08T12:34:56′ are equivalent.

Date and Time in ABAP

ABAP provides two predefined data types to handle dates (TYPE D) and times (TYPE T). Additionally, there is a data element SYST_TZONE (an integer) to describe a time zone as the time difference to UTC in seconds. Hence, date and time information is being split up into several fields.

But there are also options to handle time stamps in single fields and to use those fields for time stamp calculations (see ABAP class CL_ABAP_TIMESTAMP_UTIL, for example). The following data elements represent timestamps. While they use different underlying data types they are all constructed as a concatenation of year, month, day, and time of day.

Data Element Data Type ABAP Type Example
TIMESTAMP[1] DEC 15 P LENGTH 8 20160708123456
TIMESTAMPL[2] DEC 21,7 P LENGTH 11 DECIMALS 7 20160708123456.1234567
TZNTSTMPSL NUMC 15 N LENGTH 15 020160708123456
TZNTSTMPLL NUMC 21 N LENGTH 21 201607081234561234567

Still, any time zone information needs to be kept separately.

Mapping

This separation is the main issue when trying to translate date and time information between ABAP and OData. In general, the OData Library in SAP Gateway Foundation is only able to serialize one ABAP field into one OData primitive property and to de-serialize a property into one ABAP field. Separate timestamp and time zone information can neither be combined into a single Edm.DateTimeOffset property nor can such a property be split up into several ABAP fields.

As a result, any content of a property of type Edm.DateTimeOffset in an OData request payload or in the request URI is converted and provided to the data provider of the service in UTC. The time zone information gets lost. An OData response created by SAP Gateway Foundation may only expose date and time content in UTC. Time zone information is not added in the OData response since it is not clear which time zone is supposed to be used.

The usage of conversion exits (see ‘Conversions in SAP Gateway Foundation – Part 1‘) to split Edm.DateTimeOffset information or combine ABAP fields is not possible. SAP Gateway Foundation does not provide any means to model such relationships.

Hence, time zone information can only be handled by the data provider of the service. It is not possible to expose it correctly as part of an Edm.DateTimeOffset property but only as a separate property of type Edm.Int32, for example. The client implementation would need to implement the translation from and into a desired representation.

Therefore, we can stick to Edm.DateTime when summarizing the mapping in a small example. The following screenshots show a sample piece of implementation in /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_ENTITYSET:

DATA: 
  BEGIN OF ls_entity,
        key      TYPE int8,
        dt_date  TYPE d,
        dt_dts   TYPE timestamp,
        dt_nts   TYPE tzntstmpsl,
        dt_dtsl  TYPE timestampl,
   END OF ls_entity.

   ls_entity-key = 2.

   " Date
   " TYPE D
   ls_entity-dt_date = '17530101'.                "YYYYMMDD

   " short timestamp in decimal (DEC 15) and numerical (NUMC 15) format
   " TYPE TIMESTAMP
   ls_entity-dt_dts = 20160708123456.             "YYYYMMDDhhmmss
   " TYPE TZNTSTMPSL
   ls_entity-dt_nts = 20160708123456.             "YYYYMMDDhhmmss

   " long timstamp in decimal (DEC 21,7) format
   " TYPE TIMESTAMPL
   ls_entity-dt_dtsl = '20160708123456.1234567'.  "YYYYMMDDhhmmss.fffffff
   " TYPE TZNTSTMPLL
   " cannot be used

The corresponding ATOM response would be:

And, a JSON response looks like:

Please observe that SAP Gateway Foundation is not able to handle ABAP fields of type TZNTSTMPLL. It can only translate numerical timestamp information of length 15 providing the information to the OData Library as packed number of length 8. If you need to use sub-seconds please choose the decimal representation DEC 21, 7 (data element TIMESTAMPL) in your service implementation.

Dates are exposed with time 00:00:00. And, if the number of decimals defined by the precision of Edm.DateTime or Edm.DateTimeOffset is lower than the internal number of decimals for sub-seconds the remainder is cut off – no rounding takes place. Similarly, trailing zeros are added to the ticks in the JSON representation if required and micro-/nano-seconds are cut off.

Specialties

OData version 2.0 initially specified Jan 1, 1753 as the lower boundary for dates to avoid ambiguities with the Julian Calendar while version 4.0 just refers to the Proleptic Gregorian Calendar (including projected dates before Jan 1, 1583) but also allows for year 0 and negative years. In any case, the initial values of the ABAP data types do not have a corresponding representation in Edm.DateTime.

Therefore, the OData library in SAP Gateway Foundation serializes an initial ABAP date / time value to NULL in the OData response if the corresponding property is nullable. If the property is not nullable an exception is raised that results in an error response.

Additionally, SAP Gateway Foundation does not take any potential lower boundary into account but just translates the ABAP value. Decimal value 9121123000000 would result in an ATOM representation 0912-11-23T00:00:00 – the birthday of Otto I.

We have seen that the JSON representation works with milliseconds relative to midnight Jan 1, 1970. The type is a JSON string. In such a JSON string, SAP Gateway Foundation also accepts the ATOM format of Edm.DateTime or Edm.DateTimeOffset in request payloads.

None of the OData date and time representations includes a daylight savings time indicator. Times between 2:00 and 3:00 in the night when daylight savings time ends cannot be expressed without ambiguity.

Let us finish with a remark on conversion exits. With the former SAP GUI is was sometimes necessary to format timestamps into a kind of external representation. Conversion exit TIMES does such a conversion and might be attached to a timestamp domain in the ABAP Dictionary. Not only does this exit convert the timestamp with system time zone SY-ZONLO it also creates a character-like representation using the WRITE statement (please refer to the ABAP documentation). Such a representation can neither be handled by SAP Gateway Foundation nor does it make sense to work with such a representation that has nothing to do with the OData format. Therefore, please make sure not to use domains with those conversion exits or to switch off the conversion as explained in ‘Conversions in SAP Gateway Foundation – Part 1‘.

 

[1] Or TZNTSTMPS

[2] Or TZNTSTMPL

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply