How can I get Time format "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" in EPL

Hi All,

I have created an EPL application below is snippet code

/** Basic event definitions */
using com.apama.cumulocity.ManagedObject;
using com.apama.cumulocity.FindManagedObject;
using com.apama.cumulocity.FindManagedObjectResponse;
using com.apama.cumulocity.FindManagedObjectResponseAck;
using com.apama.correlator.timeformat.TimeFormat;
using com.apama.cumulocity.Measurement;
using com.apama.cumulocity.MeasurementValue;
using com.apama.cumulocity.MeasurementFragment;
using com.apama.cumulocity.FindMeasurement;
using com.apama.cumulocity.FindMeasurementResponse;
using com.apama.cumulocity.FindMeasurementResponseAck;

using com.apama.cumulocity.Alarm;
using com.apama.cumulocity.FindAlarm;
using com.apama.cumulocity.FindAlarmResponse;
using com.apama.cumulocity.FindAlarmResponseAck;

using com.apama.cumulocity.Event;
using com.apama.cumulocity.FindEvent;
using com.apama.cumulocity.FindEventResponse;
using com.apama.cumulocity.FindEventResponseAck;

using com.apama.cumulocity.Operation;
using com.apama.cumulocity.FindOperation;
using com.apama.cumulocity.FindOperationResponse;
using com.apama.cumulocity.FindOperationResponseAck;

using com.apama.cumulocity.ObjectCommitted;
using com.apama.cumulocity.ObjectCommitFailed;

/** Miscellaneous utilities */
using com.apama.cumulocity.Util;
using com.apama.util.AnyExtractor;
using com.apama.cumulocity.GenericRequest;
using com.apama.cumulocity.GenericResponse;
using com.apama.cumulocity.GenericResponseComplete;
using com.apama.exceptions.Exception;

monitor DigiTankMonitor {
/** Initialize the application */

action onload() {
    createVolumeCompute();
}

action createVolumeCompute() {
    monitor.subscribe(MeasurementFragment.SUBSCRIBE_CHANNEL);
    //listen on all measurements of a specific type/fragment,series/
    //on all at(*/10, *, *, *, *)
    on all MeasurementFragment() as mf {
       
       

		log "TESTING mf.value : " +   mf.value.toString() +mf.source  at INFO;
        TimeFormat timeFormat := new TimeFormat;
        if(mf.value >= 0.0){
            send Measurement("", "newType", mf.source,timeFormat.getSystemTime(), {
                newFragment:{
                    newSeries: MeasurementValue(mf.value, "newUnit2", new dictionary<string,any>)
                }
            }, new dictionary<string,any>) to Measurement.SEND_CHANNEL;
        }
    }
}

}

here I am getting below details

“time”: “2023-11-16T12:21:00.698+01:00”,
“Test”: {
“Test”: {
“unit”: “newUnit2”,
“value”: 28.88875
}
}

but I want time format as “yyyy-MM-dd’T’HH:mm:ss.SSS’Z’”
ex. 2023-11-16T11:22:00.000Z
can anyone help me on this?

Hi Chandra Shekhar,

You can try using - TimeFormat.format(currentTime, “yyyy-MM-dd’T’HH:mm:ss.SSS’Z’”), which converts the parameter to the local time and returns that time in the format specified.

Thanks,
Divya K

2 Likes

Hi Divya,

Thanks for your reply.

I tried it but not working

Thanks,
Chandra

Hi Chandra Shekhar,

Can you please explain what was the issue

Thanks,
Divya K

Hi Divya,

Still same time format issue “time”: “2023-11-20T08:13:43.101+01:00”
but I want time in “yyyy-MM-dd’T’HH:mm:ss.SSS’Z’” format

Thanks,
Chandra
.

I think @Divya.Krishnamurthy 's approach will not help you much here as EPL expects the timestamp as a float and then converts it itself into the ISO timestamp. The timezone it uses for this I think depends on the timezone of C8Y. Can you confirm on which C8Y instance you are running? On eu-latest I am getting timestamps in UTC with the “Z” timezone marker.

Btw, in both cases the format is valid ISO8601 and you should not rely on it being in a specific timezone. In fact users and devices can provide whatever timezone they want or need. Any modern programming language builtin datetime functionality should be able to handle both cases correctly.

When you receive a measurement with its time in UTC as a float, you can create a string expressing the date in UTC using the formatUTC(time, format) function.

string utcTimeStr := TimeFormat.formatUTC(myMeasurement.time, “yyyy-MM-dd’T’HH:mm:ss.SSS’Z’”)

Hi Harald,
Below is the details.

image

Does formatWithTimezone() help you?
TimeFormat.html#formatWithTimeZone() (documentation.softwareag.com)

See also: Format specification for the TimeFormat functions (documentation.softwareag.com)
And: Supported time zones (documentation.softwareag.com)

@C.shekhar_Singh I have sent you a PM asking for the URL of the tenant so that I can determine which instance you are using.

@Kevin_Palfreyman and @joel.dockray suggest help you in formatting the timestamps you receive from C8Y in EPL. They will not affect how C8Y returns the timestamps to other callers of the API though.

Hi @Harald_Meyer ,

Reverted back with details

Thanks,
Chandra

ok, I confirmed that this instance is indeed running in CET timezone, which explains the behavior you observe. Measurements you store from EPL in C8Y will be in CET (+01:00) and you cannot change that behavior. As mentioned above, when you receive the measurements back from C8Y in your EPL code, you can use the examples provided to create a representation using UTC.

Hi @Harald_Meyer ,

Thanks for your confirmation.

How can we change this instance from CET timezone to UTC timezone.
So if this instance run in UTC timezone issue will resolve for me. Is that correct??

Hi Chandra,

this is not something you can change. As I mentioned above, you should make sure that the code that is handling the timestamps can work with them correctly regardless of the used time zone. Otherwise you might run into problems in the future if for whatever reason a different time zone is used.

For example, here I created four measurements with different time zones:

| id            | time                               | type               | source.id       | c8y_Winding.temperature.value | c8y_Winding.temperature.unit |
|---------------|------------------------------------|--------------------|-----------------|-------------------------------|------------------------------|
| 71641894      | 2023-11-21T06:30:00.000+03:00      | MyMeasurement      | 4671452838      | 13                            | °C                           |
| 71647061      | 2023-11-21T08:30:00.000+03:00      | MyMeasurement      | 4671452838      | 13                            | °C                           |
| 71645905      | 2023-11-21T11:45:00.000+01:00      | MyMeasurement      | 4671452838      | 13                            | °C                           |
| 71647060      | 2023-11-21T12:00:00.000Z           | MyMeasurement      | 4671452838      | 13                            | °C                           |

Hi Harald,

Is there any way in EPL where I can handle timestamps So that I can get UTC time format?
else it would be better
You can take my snippet ELP code as reference then Could you please suggest me where should I handle timestamps So that I can get UTC time format
ie. 2023-11-21T12:00:00.000Z ?

I think this change would allow you to add a string to your measurement containing the UTC date and time.

	   	float systemTime := TimeFormat.getSystemTime();
        send Measurement("", "newType", mf.source, systemTime, {
            "newFragment":{
                "newSeries": MeasurementValue(mf.value, "newUnit2", new dictionary<string,any>)
            }
        }, { "timeUTC": <any>TimeFormat.formatUTC(systemTime, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")}) to Measurement.SEND_CHANNEL;

Here’s my code that gets an incoming measurement and uses the time from that (it has the format “2023-11-21T19:00:00.000+01:00” ) and creates a new measurement with a time (equal to incoming time) in UTC format.

action createVolumeCompute() {
monitor.subscribe(MeasurementFragment.SUBSCRIBE_CHANNEL);
//listen on all measurements of a specific type/fragment,series/
//on all at(*/10, *, *, *, *)
on all MeasurementFragment(type=“sol_TankMeasurement”,valueFragment=“sol_TankMeasurement”, valueSeries = “Empty_Airspace”) as mf {
string newType :=“sol_TankMeasurement”;
string newFragment :=“sol_TankMeasurement”;
string newSeries := “TankLiquidVolume”;
TimeFormat timeFormat := new TimeFormat;
TimeFormat floattimeFormat := new TimeFormat;
log "TESTING mf.value : " + mf.value.toString() +mf.source + timeFormat.formatUTC(mf.time,“yyyy-MM-dd’T’HH:mm:ss.SSS’Z’” ) at INFO;

    if(mf.value >= 0.0){

            send Measurement("", "newType", mf.source,floattimeFormat.parseTimeUTC("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",timeFormat.formatUTC(mf.time,"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" )), {
        
            newFragment:{
                newSeries: MeasurementValue(mf.value, "newUnit2", new dictionary<string,any>)
            }
        }, new dictionary<string,any>) to Measurement.SEND_CHANNEL;
    }
}

}
}

Result…

Hi Robert,

I do not think this actually solves the issue. It works for you because you are testing on an instance where Apama is running in UTC. You can validate this by trying to produce a timestamp in any other timezone than UTC. This will not be possible. In fact, this

mf.source,floattimeFormat.parseTimeUTC("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",timeFormat.formatUTC(mf.time,"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ))

is unnecessary and can be replaced by

mf.time

to achieve exactly the same effect in your case.

The problem occurs is because the event types expose time a float:
https://documentation.softwareag.com/pam/10.15.3/en/webhelp/related/ApamaDoc/com/apama/cumulocity/Measurement.html#time

So there is no timezone information attached to any measurement, event, or alarm you produce in an EPL App. When Apama does the C8Y API call to create them, it will use the timezone it is running in for the conversion from float into a valid timestamp string in C8Y. That’s why you are seeing UTC timestamps and Chandra is seeing CET timestamps.

@joel.dockray provided a workaround by putting the converted string into a custom field but proper solution in my opinion is still to make sure whatever code is consuming the timestamps can work with all valid ISO8601 timestamps and does not rely on a timezone designator “Z”.