Working with dates and times

Medallia Experience Cloud treats date and time as a special kind of data. Expressions that reference dates or time can perform operations specific to this kind of data, such as extracting the month from a date, getting the difference in hours between two dates, or expressing a date in a different formatting pattern, etc.

Date types

Experience Cloud accepts different types of time and date objects. Primarily, it stores and handles dates as Joda Time type, but other types can also be used:

The format a date is stored in can be verified by looking at the importer script used to import the data, or alternatively, the script that populates the field. The table below shows the types that result from common ways to create dates:

TypeScript to create
org.joda.time.DateTime object mydate = date(e_responsedate);
JavaScript Date objectmydate = new Date();
java.util.Date object mydate = e_responsedate;
JavaScript string (not recommended)mydate = Date();

If the script that originated the variable is not available, use the functions below to figure out its type. Use the k-field editor.

  • Use the typeof function to tell if the variable is a string.

    return typeof mydate;
    The result of this could either be string or object, but doesn't distinguish between different types of objects.
  • If the variable is an object, use getclass().getName() to tell the type of object.

    mydate.getClass().getName();

Use the following operations to transform date objects from one type to another:

  • To transform a JavaScript Date object into an org.joda.time.DateTime object, wrap it in a date() operation:

    date(new Date());
  • To transform a Java.util.Date object into an org.joda.time.DateTime object, wrap it in a date() operation:

    date(e_responsedate);
  • To transform an org.joda.time.DateTime object into a Java.util.Date object, use the toDate() operation:

    mydate.toDate();

    For example, see the code below used to shift the timezone for an org.joda.time.DateTime object from PDT to CET, and, then convert this object to a Java.util.Date object, since formatDate() only works with Java.util.Date objects:

    var claimJodaDateCET = date(e_zurich_ch_claim_creation_datetime).withZone(org.joda.time.DateTimeZone.forID('Europe/Berlin')).withZoneRetainFields(org.joda.time.DateTimeZone.forID('US/Pacific'));
    var claimJavaDateCET = claimJodaDateCET.toDate();
    var formattedClaimJavaDateCET = formatDate(claimJavaDateCET, 'dd.MM.yyyy');

Additionally, use the following operation to transform strings into date objects:

  • To transform a JavaScript string into an org.joda.time.DateTime object, use a parse() operation with a DateTimeFormatter method as a parameter:

    DateTime.parse("04/02/2022 20:27:05", DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss"));

Date and time operations

Use the following expressions in JavaScript code, for example, when defining K-fields or Importers. They assume that a date field called mydate exists and can be referenced. Some expressions also reference a second date called mydate2.

Important: The following expressions can only be performed on an object of type org.joda.time.DateTime. When dealing with a JavaScript Date object or a Java.util.Date object, first transform it into a Joda-Time object by wrapping it in a date() operation.
date(myDate).getYear()

Generally, these operations must be placed in the context of a function, like shown in the example below:

(function() {
	return mydate.getYear();
})();

Chain operations together by placing a . in between them. Each operation in a chain is evaluated over the result of the previous operation. For example, in the following expression, the plusHours() operation acts upon mydate and adds two hours to it. The isBeforeNow() operation works on the previous result and evaluates if the new date is before the present date, returning True or False.

return mydate.plusHours(2).isBeforeNow();

Date formatting operations

Restriction: The formatDate() function is available for k-fields but not for Importers.
Restriction: The a_invite_first_opened_date A-field is deprecated. Instead, use field a_email_invite_first_opened which mimics the obsolete field.

The formatDate() operation takes a date and returns it in any notation format, below are a few examples:

Example OutputOperation
2017-10-18T20:46:24.000-0700formatDate(mydate, "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
8:46 PM, PDTformatDate(mydate, "K:mm a, z");
Wed, Oct 18, '17formatDate(mydate, "EEE, MMM d, ''yy");
Note: See Date and time formatting for a full reference of the date and time format notation and more examples of how to structure it.

Date manipulation operations

DescriptionOperation
Get year from datemydate.getYear()
Get month from datemydate.getMonthOfYear()
Get day of week from datemydate.getDayOfWeek()
Add two days to a datemydate.plusDays(2)
Determine if a date hasn't occurred yet (this operation returns True or False)mydate.isBeforeNow()
Get the difference in full 24 hour days between two dates daysDifferenceBy24Hours(mydate, mydate2)
Restriction: The daysDifferenceBy24Hours(mydate, mydate2) function is available for k-fields but not for Importers.
Warning: For years greater than or equal to 2,000, the value returned by getYear() is 100 or greater. For example, if the year is 2026, getYear() returns 126. For information about getYear(), see the Mozilla developer reference.

Time manipulation operations

DescriptionOperation
Get the difference in hours between two timeshoursDifference(mydate, mydate2)
Convert a time to a different time zonemydate.withZone(org.joda.time.DateTimeZone.forID('Europe/London')
Add two hours to a timemydate.plusHours(2)
Restriction: These functions are available for k-fields but not for Importers. For importers consider using program_interval = new org.joda.time.Interval(start_date, end_date) to achieve similar results.
Note: You can find more date and time related operations in the Joda-Time library site.

Tips and considerations

Most often, you should rely on the operations and expressions listed above to define K-fields or Importers. However, some cases might merit a different strategy.

In certain contexts, some Date fields are returned as an array of long integers. For example, see the fields used in the action (particularly e_bp_annual_survey_start_date and e_bp_annual_survey_end_date) in the Omni Exporter event below:

{
  "changedEntities" : [ {
    "q_bp_portal_survey_firstname_txt" : null,
    "q_bp_portal_survey_program_alt" : null,
    "q_bp_portal_survey_email_txt" : null,
    "q_bp_portal_survey_language_alt" : null,
    "a_surveyid" : 336042,
    "e_bp_portal_survey_start_date" : [2021,12,2],
    "e_bp_portal_survey_end_date" : [2021,12,27]
  } ]
}

In this case, Date is internally represented as an array with 3 elements: [yyyy, MM, dd] in the JSON structure. To process this array with a string format, use the following approach:

  var fieldToDate = function (field) {
    if (!isArray(field)) {
      return null;
    }
  
    return formatDate(
      new Date(
        field[0],
        field[1] - 1,
        field[2]
      ),
      'yyyy-MM-dd'
    );
  };

The function formatDate() returns a JavaScript Date object, where the initial position in the array represents the year, the second position represents the month, and the third position represents the day of the month.

Tip: To find the position of an element in the array, bear in mind that in this case they are zero based: the first item has an index of 0.
Note: To represent months in the new Date object, you need yo subtract one because JavaScript month date is zero based, while the array uses one-based indexing for months.

Common errors

Illegal instant due to timezone offset transition

This usually indicates that a org.joda.time.DateTime operation was used to update an object to a date that does not exist. This is usually because the date falls on a daylight savings time transition.

Change the script to avoid this. For example, use the withMillis() operation to set the date of a org.joda.time.DateTime object while accounting for time shifts. The getMillis() method can be used to get the Unix timestamp of an object, also avoiding this problem. Check the org.joda.time.DateTime documentation for details.

TypeError: Cannot find function [X] in object [Time]

This indicates that an invalid method was used on an object. For example, getHours() will not work on an org.joda.time.DateTime object because that method does not exist for that object type. Reference the object's documentation and use the correct method.

Dates in conditions

When working with import conditions that refer to a period of time, express the time in days months and years as follows:

  • The number of days followed by d, as in 35d.

  • The number of months followed by m, as in 4m.

  • The number of years followed by y, as in 2y.

So, for example, a condition could refer to the field e_record_creationdate, use the operator Date in last interval and have the value 35d.