Mastering Date Comparisons in Genesys Cloud Architect: DateTimeDiff vs GetDayOfWeek

Mastering Date Comparisons in Genesys Cloud Architect: DateTimeDiff vs GetDayOfWeek

What You Will Build

  • You will construct robust routing logic in Genesys Cloud CX Architect that accurately evaluates time deltas and specific days of the week to direct conversations.
  • You will use the Genesys Cloud CX Architect Expression API to validate syntax and test complex date expressions before deployment.
  • You will use Python with the Genesys Cloud CX REST API to automate the verification of these expression behaviors.

Prerequisites

  • OAuth Client Type: Service Account or Client Credentials flow.
  • Required Scopes: architect:expression:read, architect:expression:write (if testing via API), and architect:flow:read.
  • SDK Version: Genesys Cloud CX Python SDK (genesyscloud) version 10.0.0 or higher.
  • Language/Runtime: Python 3.9+.
  • External Dependencies: pip install genesyscloud

Authentication Setup

Before interacting with the Architect Expression API, you must establish an authenticated session. The Genesys Cloud CX Python SDK handles token caching and refresh automatically when using the PlatformClient pattern, but for script-based automation, explicit initialization is required.

import os
from genesyscloud import PlatformClient
from genesyscloud.architect.api import expression_api

# Environment variables must be set:
# GENESYS_CX_REGION (e.g., mypurecloud.com)
# GENESYS_CX_CLIENT_ID
# GENESYS_CX_CLIENT_SECRET

def get_platform_client():
    """
    Initializes the Genesys Cloud Platform Client.
    """
    client_id = os.getenv("GENESYS_CX_CLIENT_ID")
    client_secret = os.getenv("GENESYS_CX_CLIENT_SECRET")
    region = os.getenv("GENESYS_CX_REGION")

    if not all([client_id, client_secret, region]):
        raise EnvironmentError("Missing required environment variables for Genesys Cloud authentication.")

    platform_client = PlatformClient(
        client_id=client_id,
        client_secret=client_secret,
        region=region
    )
    return platform_client

# Initialize the client once
platform_client = get_platform_client()
expression_api_instance = expression_api.ExpressionApi(platform_client)

Implementation

Step 1: Understanding the Core Functions

In Genesys Cloud CX Architect, date and time manipulation relies on two distinct paradigms: duration calculation and calendar component extraction.

  1. DateTimeDiff: Calculates the difference between two timestamps in a specified unit (seconds, minutes, hours, days). This is a scalar operation. It returns a number.
  2. GetDayOfWeek: Extracts the day index from a single timestamp. This is a component extraction operation. It returns an integer (0 for Sunday, 1 for Monday, …, 6 for Saturday).

A common mistake is attempting to use DateTimeDiff to determine if a conversation occurred on a Tuesday. This is inefficient and error-prone. Conversely, using GetDayOfWeek to determine if a conversation is “older than 24 hours” is impossible.

Scenario A: Using DateTimeDiff for Age-Based Routing

You want to route a callback request to a specialized team if the request is older than 48 hours.

Expression Syntax:

DateTimeDiff(Now(), callback.requestedTimestamp, "hours") > 48

Python Validation:
We will use the POST /api/v2/architect/expressions/validate endpoint to ensure this expression is syntactically correct and logically sound.

from genesyscloud.architect.model import ExpressionValidateRequest
from genesyscloud.rest import ApiException

def validate_datetime_diff_expression():
    """
    Validates a DateTimeDiff expression to check if a timestamp is older than 48 hours.
    """
    # Define the expression string
    expression_str = 'DateTimeDiff(Now(), "2023-10-01T10:00:00Z", "hours") > 48'
    
    # Note: In a real flow, you would use a variable like callback.requestedTimestamp.
    # For validation, we use a static ISO 8601 string to ensure the parser accepts the type.
    
    request_body = ExpressionValidateRequest(
        expression=expression_str,
        # Optional: Provide sample data to test evaluation
        # data={ "callback": { "requestedTimestamp": "2023-10-01T10:00:00Z" } }
    )

    try:
        response = expression_api_instance.post_architect_expressions_validate(
            body=request_body
        )
        
        print(f"Expression Valid: {response.valid}")
        print(f"Result Type: {response.result_type}")
        if response.errors:
            print("Errors:", [e.message for e in response.errors])
        else:
            print("No syntax errors found.")
            
    except ApiException as e:
        print(f"Exception when calling ExpressionApi->post_architect_expressions_validate: {e}\n")

validate_datetime_diff_expression()

Key Insight:
The DateTimeDiff function signature is DateTimeDiff(timestamp1, timestamp2, unit). The unit must be one of: seconds, minutes, hours, days, weeks, months, years. The result is always a numeric value. If timestamp1 is earlier than timestamp2, the result is negative.

Step 2: Using GetDayOfWeek for Calendar-Based Routing

You want to route calls to a specific queue only on Mondays and Tuesdays.

Expression Syntax:

GetDayOfWeek(Now()) == 1 OR GetDayOfWeek(Now()) == 2

Python Validation:

def validate_day_of_week_expression():
    """
    Validates a GetDayOfWeek expression to check if today is Monday or Tuesday.
    """
    # 1 = Monday, 2 = Tuesday
    expression_str = 'GetDayOfWeek(Now()) == 1 OR GetDayOfWeek(Now()) == 2'
    
    request_body = ExpressionValidateRequest(
        expression=expression_str
    )

    try:
        response = expression_api_instance.post_architect_expressions_validate(
            body=request_body
        )
        
        print(f"Expression Valid: {response.valid}")
        print(f"Result: {response.result}") # Should be true or false depending on current day
        
    except ApiException as e:
        print(f"Exception when calling ExpressionApi->post_architect_expressions_validate: {e}\n")

validate_day_of_week_expression()

Key Insight:
GetDayOfWeek returns an integer. The mapping is strict:

  • 0: Sunday
  • 1: Monday
  • 2: Tuesday
  • 3: Wednesday
  • 4: Thursday
  • 5: Friday
  • 6: Saturday

Do not use string comparisons like GetDayOfWeek(Now()) == "Monday". This will result in a type mismatch error in the Architect engine.

Step 3: Combining Both for Complex Business Logic

A common requirement is: “Route to the ‘Urgent’ queue if the ticket was created today (same day) AND the current time is within business hours (9 AM - 5 PM).”

This requires:

  1. Checking if the day of the creation timestamp matches the day of Now().
  2. Checking if the current hour is between 9 and 17.

Expression Syntax:

GetDayOfWeek(Now()) == GetDayOfWeek(ticket.createdDate) AND GetHour(Now()) >= 9 AND GetHour(Now()) < 17

Python Validation:

def validate_combined_date_logic():
    """
    Validates a complex expression combining day-of-week matching and hour checks.
    """
    # We simulate a ticket created today
    # In a real flow, ticket.createdDate is a variable.
    # For validation, we must provide a valid timestamp string that represents "today"
    # However, the validator does not execute with live 'Now()', it checks syntax.
    # To test logic, we rely on the 'data' parameter if available, or simply trust the syntax.
    
    expression_str = 'GetDayOfWeek(Now()) == GetDayOfWeek(ticket.createdDate) AND GetHour(Now()) >= 9 AND GetHour(Now()) < 17'
    
    request_body = ExpressionValidateRequest(
        expression=expression_str,
        # Providing mock data to help the validator infer types
        data={
            "ticket": {
                "createdDate": "2023-10-27T10:00:00Z" # Example timestamp
            }
        }
    )

    try:
        response = expression_api_instance.post_architect_expressions_validate(
            body=request_body
        )
        
        if response.valid:
            print("Complex expression is syntactically valid.")
            print(f"Expected Result Type: {response.result_type}")
        else:
            print("Expression is invalid.")
            if response.errors:
                for err in response.errors:
                    print(f"Error: {err.message} at index {err.start}")
            
    except ApiException as e:
        print(f"Exception when calling ExpressionApi->post_architect_expressions_validate: {e}\n")

validate_combined_date_logic()

Why this works:

  • GetDayOfWeek extracts the integer day index from both Now() and the ticket’s createdDate.
  • Comparing two integers (==) is a valid boolean operation.
  • GetHour extracts the integer hour (0-23) from Now().
  • The logical AND combines these boolean results.

Complete Working Example

The following Python script encapsulates the validation of both patterns. It demonstrates how to programmatically verify your Architect expressions before deploying them to production flows.

import os
import sys
from genesyscloud import PlatformClient
from genesyscloud.architect.api import expression_api
from genesyscloud.architect.model import ExpressionValidateRequest
from genesyscloud.rest import ApiException

def setup_client():
    """Initializes the Genesys Cloud Platform Client."""
    client_id = os.getenv("GENESYS_CX_CLIENT_ID")
    client_secret = os.getenv("GENESYS_CX_CLIENT_SECRET")
    region = os.getenv("GENESYS_CX_REGION")

    if not all([client_id, client_secret, region]):
        raise EnvironmentError("Missing required environment variables.")

    return PlatformClient(
        client_id=client_id,
        client_secret=client_secret,
        region=region
    )

def validate_expression(expression_str, data=None, description=""):
    """
    Validates a single expression against the Genesys Cloud API.
    
    Args:
        expression_str (str): The Architect expression string.
        data (dict, optional): Sample data for type inference.
        description (str): A human-readable description of the test.
    """
    platform_client = setup_client()
    expression_api_instance = expression_api.ExpressionApi(platform_client)
    
    request_body = ExpressionValidateRequest(
        expression=expression_str
    )
    if data:
        request_body.data = data

    print(f"\n--- Testing: {description} ---")
    print(f"Expression: {expression_str}")

    try:
        response = expression_api_instance.post_architect_expressions_validate(
            body=request_body
        )
        
        if response.valid:
            print("Status: VALID")
            print(f"Result Type: {response.result_type}")
            if response.result is not None:
                print(f"Evaluated Result: {response.result}")
        else:
            print("Status: INVALID")
            if response.errors:
                for error in response.errors:
                    print(f"  Error: {error.message} (Start: {error.start}, End: {error.end})")
            else:
                print("  No specific error message provided.")
                
    except ApiException as e:
        print(f"API Exception: {e.status} {e.reason}")
        print(f"Response Body: {e.body}")

def main():
    """Runs a suite of expression validation tests."""
    
    # Test 1: DateTimeDiff for Age-Based Routing
    # Logic: Is the callback requested more than 48 hours ago?
    # Note: Using a static past date for demonstration.
    test_data_1 = {
        "callback": {
            "requestedTimestamp": "2023-10-01T10:00:00Z" 
        }
    }
    validate_expression(
        expression_str='DateTimeDiff(Now(), callback.requestedTimestamp, "hours") > 48',
        data=test_data_1,
        description="DateTimeDiff: Check if callback is older than 48 hours"
    )

    # Test 2: GetDayOfWeek for Weekday Routing
    # Logic: Is today Monday (1) or Tuesday (2)?
    validate_expression(
        expression_str='GetDayOfWeek(Now()) == 1 OR GetDayOfWeek(Now()) == 2',
        description="GetDayOfWeek: Route only on Mon/Tue"
    )

    # Test 3: Combined Logic (Same Day + Business Hours)
    # Logic: Is the ticket created today AND is it between 9 AM and 5 PM?
    test_data_3 = {
        "ticket": {
            "createdDate": "2023-10-27T14:00:00Z" # Assuming today is Oct 27
        }
    }
    validate_expression(
        expression_str='GetDayOfWeek(Now()) == GetDayOfWeek(ticket.createdDate) AND GetHour(Now()) >= 9 AND GetHour(Now()) < 17',
        data=test_data_3,
        description="Combined: Same Day and Business Hours"
    )

    # Test 4: Common Error - String Comparison for Day
    # This should fail or return false depending on engine strictness, but usually fails type check
    validate_expression(
        expression_str='GetDayOfWeek(Now()) == "Monday"',
        description="Error Case: Comparing Day Index to String"
    )

if __name__ == "__main__":
    main()

Common Errors & Debugging

Error: 400 Bad Request - Invalid Expression Syntax

Cause: The expression string contains a syntax error, such as a missing parenthesis, incorrect function name, or unsupported operator.
Fix: Use the post_architect_expressions_validate API endpoint. The response will include an errors array with start and end indices pointing to the exact character location of the error.
Code Fix:

# Check response.errors in your validation logic
if response.errors:
    for err in response.errors:
        print(f"Fix character at index {err.start}: {err.message}")

Error: Type Mismatch - Cannot Compare Integer to String

Cause: Using GetDayOfWeek(Now()) == "Monday". GetDayOfWeek returns an integer (0-6).
Fix: Use the integer value. GetDayOfWeek(Now()) == 1 for Monday.
Code Fix:

# Incorrect
GetDayOfWeek(Now()) == "Monday"

# Correct
GetDayOfWeek(Now()) == 1

Error: DateTimeDiff Returns Negative Value

Cause: The order of arguments in DateTimeDiff(timestamp1, timestamp2, unit) determines the sign. DateTimeDiff(OlderDate, NewerDate, "hours") returns a positive number. DateTimeDiff(NewerDate, OlderDate, "hours") returns a negative number.
Fix: Ensure the older timestamp is the first argument if you expect a positive age. Or use absolute value functions if available, or simply check < -48.
Code Fix:

# To check if 'createdDate' is older than 'Now()' by 48 hours:
DateTimeDiff(Now(), createdDate, "hours") > 48

Error: 429 Too Many Requests

Cause: The Genesys Cloud CX API has rate limits. If you are validating many expressions in a loop, you may hit the limit.
Fix: Implement exponential backoff in your Python script.
Code Fix:

import time

def api_call_with_retry(func, *args, max_retries=3, backoff_factor=2):
    for attempt in range(max_retries):
        try:
            return func(*args)
        except ApiException as e:
            if e.status == 429:
                wait_time = backoff_factor ** attempt
                print(f"Rate limited. Waiting {wait_time} seconds...")
                time.sleep(wait_time)
            else:
                raise
    raise Exception("Max retries exceeded")

Official References