How to date transform in a workflow

I have date format likes
4/11/2025 16:19:51 PM UTC
4/1/2025 6:19:51 AM UTC
14/11/2025 16:19:51 AM UTC

Any idea on how can we convert to ISO8601 & compare if timestamp older than X no of days in workflow using define variable or account attribute transform

You can use date format transformation. If that does not do what you want to do then you will need to write a rule.Date Format | SailPoint Developer Community

@aaileni -

Here’s a practical, way to (1) normalize those strings to ISO-8601 and (2) check if they’re older than X days—using either an Identity Profile transform (Account Attribute) or a Workflow » Define Variable step.


1) Normalize to ISO-8601 (Account Attribute transform)

Your inputs vary by locale and hour notation and always end with UTC, e.g.:

  • 4/11/2025 16:19:51 PM UTC ⟔ malformed (24-hour + AM/PM together)

  • 4/1/2025 6:19:51 AM UTC ⟔ US style, 12-hour + AM/PM

  • 14/11/2025 16:19:51 AM UTC ⟔ malformed (24-hour + AM/PM), day-first

SailPoint’s dateFormat needs a single input pattern per attempt. Use firstValid to try multiple patterns and output ISO-8601. (It uses Java SimpleDateFormat tokens and supports the literal timezone via z.) (Date Format)

Account attribute transform (example):

{
  "name": "NormalizeLastSeenToISO",
  "type": "firstValid",
  "attributes": {
    "values": [
      {
        "name": "US_12h_AMPM",
        "type": "dateFormat",
        "attributes": {
          "input": { "type": "accountAttribute", "attributes": { "sourceName": "My Source", "attributeName": "rawLastSeen" } },
          "inputFormat": "M/d/yyyy h:mm:ss a z",
          "outputFormat": "ISO8601"
        }
      },
      {
        "name": "US_24h",
        "type": "dateFormat",
        "attributes": {
          "input": { "type": "accountAttribute", "attributes": { "sourceName": "My Source", "attributeName": "rawLastSeen" } },
          "inputFormat": "M/d/yyyy HH:mm:ss z",
          "outputFormat": "ISO8601"
        }
      },
      {
        "name": "DMY_12h_AMPM",
        "type": "dateFormat",
        "attributes": {
          "input": { "type": "accountAttribute", "attributes": { "sourceName": "My Source", "attributeName": "rawLastSeen" } },
          "inputFormat": "d/M/yyyy h:mm:ss a z",
          "outputFormat": "ISO8601"
        }
      },
      {
        "name": "DMY_24h",
        "type": "dateFormat",
        "attributes": {
          "input": { "type": "accountAttribute", "attributes": { "sourceName": "My Source", "attributeName": "rawLastSeen" } },
          "inputFormat": "d/M/yyyy HH:mm:ss z",
          "outputFormat": "ISO8601"
        }
      }
    ]
  }
}

:white_check_mark: This yields a clean ISO8601 value like 2025-11-04T16:19:51.000Z in the profile mapping.

:warning: If a source actually produces “16:19:51 PM” (24-hour + AM/PM), that is an invalid timestamp—no dateFormat pattern can correctly interpret it. Fix upstream to either HH:mm:ss z without a, or h:mm:ss a z with a 1–12 hour. (The transform docs require pattern/data agreement.) (Date Format)


2) “Older than X days?” in a Workflow (Define Variable)

dateCompare requires both sides in ISO-8601. We’ll compute threshold = now − X days via dateMath, then compare. dateMath accepts now and outputs yyyy-MM-dd'T'HH:mm; so we wrap it with a small dateFormat to standard ISO-8601 before comparing. (Date Math)

Define Variable → “thresholdISO” (Transform):

{
  "name": "thresholdISO",
  "type": "dateFormat",
  "attributes": {
    "input": {
      "name": "NowMinusXd",
      "type": "dateMath",
      "attributes": {
        "expression": "now-{{ steps.input.variables.XDays }}d",
        "roundUp": false
      }
    },
    "inputFormat": "yyyy-MM-dd'T'HH:mm",
    "outputFormat": "ISO8601"
  }
}

  • Set XDays as a preceding Workflow Input (number), or hardcode e.g. now-30d.

Define Variable → “isOlderThanXDays” (Transform):

{
  "name": "isOlderThanXDays",
  "type": "dateCompare",
  "attributes": {
    "firstDate": {
      "type": "identityAttribute",
      "attributes": { "name": "NormalizeLastSeenToISO" }
    },
    "secondDate": {
      "type": "identityAttribute",
      "attributes": { "name": "thresholdISO" }
    },
    "operator": "LTE",
    "positiveCondition": true,
    "negativeCondition": false
  }
}

  • Returns boolean. Use it directly in a Condition step (e.g., route notifications, disable accounts, etc.). dateCompare supports LT/LTE/GT/GTE and accepts "now" too, but here we compare to a computed threshold. (Date Compare)

Variants you might need

  • Working directly off an Account Attribute in Workflow
    If you don’t want to map an identity attribute, you can replace "identityAttribute" above with a nested firstValid+dateFormat that reads the account attribute using JSONPath in a Transform variable, then feed that normalized ISO-8601 into dateCompare.

  • Define Variable built-ins
    Workflows also provide date operators like Add Time in “Define Variable”, but they’re limited (≀ 1 year from original date) and don’t help with parsing non-ISO inputs. The transform approach is more robust for mixed formats. (Define Variable in ISC Workflow)


Quick testing tips

  1. Start by echoing the raw and normalized values in a test run (Log step).

  2. Verify a couple of edge dates around the threshold (e.g., exactly X days, X+1).

  3. If any feed still shows “16:
 PM”, fix the producer or pre-normalize upstream (e.g., switch to HH:mm:ss z without AM/PM).


References

Cheers!!!

1 Like

Though earlier responses provide you the ways to reformat a date string, those approaches work in transforms, and not in workflows. Currently workflows have very limited options to reformat the dates and your use case does not seem like one that’s available.

You can check “Define Variable” operator in a workflow and try “Date Formatter” step for the options available.

First step will be a variable that will read the dates from another step prior

2 Likes

It’s not allowing String must be in ISO8601 format
couldn’t convert in workflow index value is different
1/1/2025
10/1/2025
10/25/2025

We can create transform using identity profile but need to pulling attribute from non-authoritative source.
can we create transform without triggering an action to that source like “create work Item“ if user is not that source?

Easy but whacky:

Use the “Generate identity profile preview” API: generate-identity-preview | SailPoint Developer Community

In the HTTP Action call / payload, you can define a dummy transform definition, on the fly, that contains your date transform. Provide it with an explicit input date string (i.e. it doesn’t need to touch any identity attribute or any account attribute). The preview returned will be the post-transformed output.

Kind of abusing the API
.but it technically does exactly what it’s coded to do.

This approach also gives you access to Velocity Template evaluation (static Transform) to things such as list element manipulation.

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.