Skip to Content

Date and Time in SAP Gateway Foundation

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


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:

  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
   ls_entity-dt_dts = 20160708123456.             "YYYYMMDDhhmmss
   ls_entity-dt_nts = 20160708123456.             "YYYYMMDDhhmmss

   " long timstamp in decimal (DEC 21,7) format
   ls_entity-dt_dtsl = '20160708123456.1234567'.  "YYYYMMDDhhmmss.fffffff
   " 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.


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




You must be Logged on to comment or reply to a post.
  • Hi Thomas,


    Is there a way we can convert JSON timestamp into SAP?

    Currently in my webservice response I am getting date as


    I have to convert it to YYYYMMDD ABAP format.

    Thank you.


    • Hello Kethan,

      I am not aware of a re-use function that would do the job. So, I guess you need to write your own piece of ABAP.


        FIND REGEX '^\\?/Date\((-?[[:digit:]]+)([+-][[:digit:]]{1,4})?\)\\?/$'
            IN lv_value SUBMATCHES lv_ticks lv_offset.

      to extract the ticks and the offset from the JSON representation. Then calculate the seconds from lv_ticks considering lv_offset, divide by 86400 as an integer (using DIV) and add this to 19700101 to get the date.


    • In SAC feed via odata i have the output field from a CDS view   "posting date".   It shows as a AA type "character field not a "date" field .  I am not an abaper,  but I can navigate CDS views.  I think the field started as a date field in the abap table .. but where how do i tell an abaper to fix the code to make it a date field so I can use it for incremental loading.

      • It should be checked how the corresponding field is typed in the CDS View that is the basis for the OData exposure. Typing may change when views are stacked on top of the original database table. Then, the question is how the OData service was created: manual implementation on top of the CDS View, auto-exposure?

        • THanks so much..  for responding ..  just to keep it clean the view in question is the SAP delivered C_RevenueFromInvoiceQry  view.   It has various anotations that should drive odata to make a date field ..   Like @Semantics.systemDate.createdAt: true   and the tables have dats fields..

          The service is generated upon activation of the CDS view with  ODATA publish true annotation.    I have heard rumors of another way but I am resisting that because I don't know it!!! and itseems dumb that an annotation does not exist that would drive the odata to have a date field..  🙂

          • If I have to do something different to get the date field exposed.. can you point me as if I was wearing very thick glasses to how to do it set by step..  it would be very appreciated.     SAC documentation should mention this ..  it must be driving hundreds of people nuts!


          • Hello Ned. I am afraid I cannot help with that specific aspect. I can see that the OData service is an auto exposure of the mentioned CDS View and indeed provides the billing date as Edm.String. I suppose this is intended - OData V2 does not know a proper date type, it just uses Edm.DateTime which might not be suitable in this case. I am neither an expert in the analytics space nor in that specific area.

            Maybe it is a good idea to post the topic in the 'Answers' section as a question where it could get appropriate attention. Sorry. Thomas

          • Again thanks for reply..  can you lead me to where you can manually alter the CDS generated service and override the edm.string  to edm.datetime?


            best Ned

          • You have to build an OData Service using the Referenced Data Source appraoch.

            Here you can override the define( ) method in the MPC_EXT class as described here for another used case.


            METHOD define.
              DATA: lo_entity_type TYPE REF TO /iwbep/if_mgw_odata_entity_typ, 
                    lo_property  TYPE REF TO /iwbep/if_mgw_odata_property.
              super->define( ).
              "Create sap:creatable="true" annotation for product entity set  
            lo_entity_type = model->get_entity_type( zcl_z_be2ui_###_mpc=>gc_zc_be2ui_product_###type ).
              IF lo_entity_type IS NOT INITIAL.  
            lo_entity_type->set_creatable( abap_true ).  
            "Create sap:creatable="false" annotation for the key field "Product"  
            lo_property = lo_entity_type->get_property( 'Product').  
            IF lo_property IS NOT INITIAL.  
            lo_property->set_creatable( abap_false ).  
            or as described in this blog.
          • thanks for the reply..  I can't tell you how long I have been trying to find this out.!!Seems crazy that SAC would highlight this feature for incremental loading yet not mention any links to this.   Are you 100% sure this is the only way... Why do decimals output as the correct EDM type by not dates?   Why is there not a cds anotation that does this by now  🙁  ..

            Now that I have vented.. I am not really a coder..  but having worked for SAP for 23 yrs before retiring ) I am a good hacker.

            It seems that the great blogs you wrote might be dated? but I ma very nervous to procede 🙂

            1) So I go to segw then create a project with the option "service model for ref service"
            2) choose the original service then it look like I can use this screen to just force a change to the entity type...

            Does this seem like the correct thing to do..  ( venting again  - why is is so hard:)

          • It seems to stop on me... when I get to the screen to to select the ref data source wizard  the error it gives me is "CDS view XXXXXx is intended for analytics and prevents me form using it as a ref data source.


            ANy more docs you can porvide??


  • I am currently working on a OData v2 service implementation where a Function Import has (among else) one input parameter with data type Edm.DateTimeOffset

    It seems SAP Gateway can't handle positive UTC offsets for the datetimeoffset'...' function.

    datetimeoffset'2018-01-02T09:15:00Z' arrives as 20180102091500, as expected.
    datetimeoffset'2018-01-02T09:15:00-06:00' to represent the same local time in Houston (Texas, USA) arrives as 20180102151500, which is also as expected.
    datetimeoffset'2018-01-02T09:15:00+01:00' to represent the same local time in Stavanger (Norway) arrives as 20180102091500, which is not at all as expected.

    As far as I have understood the documentation I have found positive and negative offsets up to 14:00 [-14:00, 14:00] is what the standard defines. SAP Gateway seems to only handle negative offsets, but without input validation, so datetimeoffset'2018-01-02T09:15:00-24:00' arrives as 20180103091500 and even datetimeoffset'2018-01-02T09:15:00-99:00' is accepted and arrives as 20180106121500.

    • Hi Kjetil... sorry for the late reply. I didn't have the chance to check that but I would propose to open an incident with respect to this issue. Could be a bug. Thomas

      • I would if I could... Unfortunately I am not allowed to, because that requires that my S-user is "linked to" a SAP installation. It is not. However, I can prepare the case and ask if one of the employees here will do it.

  • ok thanks Thomas, I have a question since I can't seem to make it work in odata 2 with sap GW. How do I write a filter that takes a timestamp? I'm trying to select all bookings from a certain date to the hi-date - and I'm testing it in the sap gateway client:

    Bookings?$filter=CreateDate eq '2018-01-17T23:00:00' - invalid token in position 14

    And sometimes it works when I just do this, but sometimes it doesn't:

    Bookings?$filter=CreateDate eq DateTime'2018-01-17T23:00:00'

    I can swear just a few minutes ago I was getting the error invalid toke in position 22 for the statement above... could it have something to do that I was copying it from an email text, I wonder - because it was working yesterday evening. The only difference is that I deleted the DateTime part before and wrote it by hand.


    • Thanks, Kethan Uppalati. Of course, it is possible to send plain data in a certain format to the client and let the formatting happen on client-side.

      But at the end, the OData service will only expose strings somehow foiling the elaborate type system of the OData standard.

      • I want the opposite,  as others have posted I don't understand why the  CDS view accessing a DATS ABAP field outputs EDM.STRING when the odata service is executed and the meta data is reviewed.

        When the CDS view is used to send data to SAC there is a feature that relies on DATE time fields to do an incremental load.. this is critical ..

        How can this be set correctly ?  is there a semantics tag?

  • Not sure what the issue is with date.  I’ve just passed Datetime field and in the debug mode, it shows that time portion has been auto-magically filtered out.  BTW, my Netweaver stack is 7.51 SP2.

    SAP Gateway Client with OData based out of CDS View with Association.


    And debug mode of  method FLIGHTSET_GET_ENTITY.

    Filter working fine,

    Filter in debug mode,

    • Hello Kyo Choi,

      It is a bit difficult to analyze from a distance. But I assume you exposed a CDS view containing an attribute type as date (ABAP built-in type D).

      The blog describes that OData V4 introduces Edm.Date but OData V2 does not provide an appropriate data type for dates. Hence, the Gateway Foundation needs to map the ABAP date to Edm.DateTime. The metadata of the service shows Fldate as Edm.DateTime and both the key as well as the filter string need to an appropriate literal representation.

      But the Gateway Foundation framework knows that the internal representation had been an ABAP date and automatically maps accordingly. The service provider already gets the internal representation. This is the magic you are referring to. And, the mapping simply cuts of the time information.


  • Very good blog, thanks Thomas! I have one question: is it the idea that you perform the value conversion to UTC in ABAP code, and the OData only does the displaying in Epoch?

    When we have a Timestamp in ABAP for our timezone, OData displays it in epoch but the value is our timezone value, not the adjusted value to UTC. I would then have thought that SAP always does the UTC value (timezone) conversion in out and out in.


    • Hello Wouter,

      Thanks a lot. Sorry for the late reply. If I understand the question correctly: no, you do not need to convert in ABAP.

      If the client sends an OData request that specifies a timezone ≠ UTC then the OData library in the SAP Gateway Foundation framework will convert to UTC. The data provider class you would implement already gets the converted date/time in the respective ABAP format.

      If you return date/time data from your data provider class to the framework then this date/time will always be interpreted as if it would be UTC - without any conversion. Even if you stored another timezone somewhere in your database table you will not be able to provide this information to the Gateway framework.

      But: if you are able to handle time zones somehow because you store them separately and a proper handling at the client side is available then you would need to do conversions in your own ABAP code.


  • Hi Thomas,

    I kept data type as dats in my database table while creating (post method) a new record in OData. It was created when using xml format but not in json format.

    Is there any way we can convert JSON timestamp into SAP?

    Currently in my webservice response I am getting date as


    I have to convert it to YYYYMMDDHHSS ABAP format.



    Yaswanth Nakkina

    • Hello Yaswanth,

      In which context do you want to covert this information? If you specify a json payload for an OData service that is implemented with SAP Gateway Foundation, then the OData library and the Gateway framework automatically convert the data. You receive the information in the data provider class already in an ABAP format depending on the definition of your OData service.


  • Hello Thomas,

    I receive timestamp from backend in long format (ABAP Type TIMESTAMPL).

    Calling the method getMilliseconds of Edm.DateTimeOffset I make sure that correct value of milliseconds is received.

    Then I want to send the very same timestamp value to the server via ODataModel.update (v2) method. My problem is that milliseconds part is being cut from the value. Example:

    expected value 20191126130221.5254400

    got on server 20191126130221.5250000


    Would you have a suggestion how can I fix it?


    Component: SAP_GWFND 751 0007 SAP Gateway Foundation 7.40

    Ping Thomas Nitschke


    Kind regards



    • Hello Nikolay,

      I am not sure what type of OData client you are using. For OData V2, the situation is as follows:

      • If the client sends a JSON payload then only milliseconds can be handled (no smaller units) because the JSON representation is defined (!) as milliseconds in the unix age – see description in the blog post. Your example value is represented by  “\/Date(1574773341525+0000)\/” … you can guess the 525 milliseconds. 
      • If the client would use ATOM XML then the OData library in SAP Gateway Foundation is able to parse 2019-11-26T13:02:21.5254400Z into the expected backend representation with the 4.4 microseconds.

      The blog post also describes a special feature of the OData library in SAP Gateway Foundation. You can transfer an ATOM XML representation of DateTimeOffset (2019-11-26T13:02:21.5254400Z) in the value of the DateTimeOffset property in a JSON payload. Then, the result is also as expected. But this is a specialty that would need to be supported by the client.



      • Hello Thomas,

        Thank you for quick response. I have mistaken nanoseconds for milliseconds. As workaround, I will round nanoseconds on backend, as we do not really need such precision.

        Kind regards


  • It is quite interesting to use 7 digits for microseconds especially because python's datetime.strptime [0] format fails to parse Edm.DateTime values with formatting string "%Y-%m-%dT%H:%M:%S.%f". The code "%f" accepts 1-6 digits and the 7th digit is reported as an leftover.

    I have to come up with a fix for our PyOdata [1].

    What are your suggestions?

    Can we just ignore those hundreds of nanosecond?





    • Hi Jakub,

      That's an interesting topic. I am not an expert in all the specifications but it seems that both ISO 8601 as well as RFC 3339 allow for any number of digits as fractional seconds. The specifications point out that the communication partners must agree upon the usage of fractional seconds.

      As far as I can see in, OData restricts fractional seconds to 12 (!) digits. The 7 digits rather seem to be a restriction imposed by the ABAP data type - might need to correct the blog post a little.

      Ignoring extra digits is probably an option. Will try to get some more background information but can't promise.



  • Greate blog, really helpful!

    I'm experiencing some issues though... When trying to create a POST test data for timestamps (DEC15) inside the gateway client.

    No matter how I format the the dates it will always give me either cx_parameter_invalid_range with the details of "Property 'X' at offset 'Y' has invalid value 'Z'".

    Is there a way to pass that data when doing testing through the gateway client?

    • Hello Roei,

      Thanks a lot. And, sorry for the late reply.

      The exception points to the ABAP OData Library. So, I suppose there is an issue with the data format you use in the payload of your POST request.

      TIMESTAMPS should understand date + time up to seconds. Hence, an OData representation in XML would like 2020-06-09T08:13:00 and in JSON \/Date(1591683205)\/

      Please check the format of you request payload (XML or JSON) and try with examples above. If I does not work, someone would need to look into details in your system.