Mastering Date Comparisons in Genesys Cloud Architect: DateTimeDiff and GetDayOfWeek
What You Will Build
- One sentence: You will build a Genesys Cloud Architect flow that routes calls based on complex date logic, such as excluding weekends or calculating business day age.
- One sentence: This tutorial uses the Genesys Cloud Platform API to programmatically create and validate Architect flow configurations.
- One sentence: The programming language covered is Python, using the official Genesys Cloud Python SDK.
Prerequisites
- OAuth client type: Confidential Client (Client Credentials Grant).
- Required scopes:
admin(for full flow management) orflow:write/flow:readdepending on your organization’s permission set. - SDK version:
genesyscloud-python-sdkversion 140.0.0 or later. - Language/runtime: Python 3.9+.
- External dependencies:
pip install genesyscloud-python-sdk.
Authentication Setup
Authentication in Genesys Cloud relies on OAuth 2.0. For server-to-server integrations like API-driven flow management, the Client Credentials flow is the standard. The SDK handles token acquisition and refresh automatically, but you must initialize the PlatformClient with your environment and credentials.
import os
from purecloud_platform_client import Configuration, PlatformClient
from purecloud_platform_client.rest import ApiException
def init_platform_client():
"""
Initializes the Genesys Cloud Platform Client with OAuth credentials.
Assumes environment variables are set for security.
"""
config = Configuration()
# Set the base URL for your Genesys Cloud environment
# e.g., https://api.mypurecloud.com or https://api.usw2.pure.cloud
config.host = os.getenv("GENESYS_HOST", "https://api.mypurecloud.com")
# OAuth credentials
config.client_id = os.getenv("GENESYS_CLIENT_ID")
config.client_secret = os.getenv("GENESYS_CLIENT_SECRET")
if not config.client_id or not config.client_secret:
raise ValueError("GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET must be set.")
# Initialize the platform client
platform_client = PlatformClient(config)
# Verify connection by fetching the current user (optional but recommended for debugging)
try:
# This call requires the 'user:read' scope
users_api = platform_client.UsersApi()
user = users_api.get_user("me")
print(f"Authenticated as: {user.name} ({user.id})")
except ApiException as e:
print(f"Authentication or connection error: {e.status} - {e.reason}")
raise
return platform_client
Implementation
Step 1: Understanding the Expression Engine
Genesys Cloud Architect uses a proprietary expression language for conditions and data actions. When working with dates, two critical functions are DateTimeDiff and GetDayOfWeek.
DateTimeDiff calculates the difference between two datetime values in a specified unit (seconds, minutes, hours, days, etc.). It returns a numeric value.
GetDayOfWeek extracts the day of the week from a datetime value, returning an integer (typically 0 for Sunday, 1 for Monday, …, 6 for Saturday, though this can vary by locale settings in some contexts; Genesys standardizes on 0=Sunday).
To use these in an API call, you must construct the condition JSON correctly. The condition object requires an expression field (a string) and often values for comparison.
Step 2: Constructing the Weekend Exclusion Logic
A common requirement is to route calls only during business days. We will build a condition that checks if the current day is NOT Saturday (6) or Sunday (0).
The expression for GetDayOfWeek applied to the current time is:
GetDayOfWeek(CurrentTime())
To check if it is a weekend, we can check if the result is greater than 5 (Saturday) or equal to 0 (Sunday). However, a cleaner approach in Architect is to use a compound condition or a single expression that returns a boolean.
Let us construct a condition that evaluates to true if the day is a weekday.
Expression: GetDayOfWeek(CurrentTime()) > 0 AND GetDayOfWeek(CurrentTime()) < 6
In the API, this translates to a condition object. Note that the expression field in the API often expects a mathematical or logical expression that resolves to a number or boolean, depending on the operator.
For a BooleanCondition, the structure is:
{
"expression": "GetDayOfWeek(CurrentTime())",
"operator": "notIn",
"values": ["0", "6"]
}
However, notIn works best with lists. A more robust method for complex logic is using the expression field with a comparison operator.
Let us define a condition that checks if the day is Monday (1) through Friday (5).
Step 3: Building the Flow via API
We will create a new flow with a single route queue action, but first, we need to define the condition. We will use the CreateFlow endpoint.
First, we need to gather necessary IDs:
- Route Queue ID: To route the call.
- Flow Version: We are creating a new draft.
We will assume you have a Route Queue ID. If not, you can list them:
from purecloud_platform_client.rest import ApiException
def get_route_queue_id(platform_client, queue_name="Default Queue"):
"""
Finds the ID of a route queue by name.
"""
routing_api = platform_client.RoutingApi()
try:
# Search for the queue
queues = routing_api.post_routing_queues_search(
body={"query": queue_name}
)
if queues.entities and len(queues.entities) > 0:
# Return the first match
return queues.entities[0].id
else:
raise ValueError(f"No route queue found with name: {queue_name}")
except ApiException as e:
print(f"Error finding route queue: {e.status} - {e.reason}")
raise
Now, we construct the flow definition. The key part is the outboundActions or initialActions and the conditions.
We will create a flow that:
- Starts.
- Checks if the current day is a weekday using
GetDayOfWeek. - If yes, routes to the queue.
- If no, plays a message or disconnects (for simplicity, we will just end the flow or route to a different queue; here we will use a single path for brevity, but the condition logic is the focus).
Actually, to demonstrate the expression syntax clearly, we will create a flow with a BooleanCondition node.
from purecloud_platform_client.models import FlowCreateRequest, FlowDraft, FlowAction, FlowCondition, FlowRouteQueueAction
from purecloud_platform_client.models import FlowBooleanCondition, FlowStringCondition, FlowNumericCondition
def create_weekday_flow(platform_client, route_queue_id):
"""
Creates a flow that routes calls only on weekdays (Mon-Fri).
"""
flows_api = platform_client.FlowsApi()
# Define the route queue action
route_action = FlowRouteQueueAction(
id="routeToQueue",
name="Route to Queue",
route_queue_id=route_queue_id,
action_type="RouteQueue"
)
# Define the condition: GetDayOfWeek(CurrentTime()) > 0 AND < 6
# In Genesys API, complex logic is often handled by chaining conditions or using expressions.
# For a simple numeric check, we can use a NumericCondition.
# Condition: GetDayOfWeek(CurrentTime()) > 0
start_of_week_condition = FlowNumericCondition(
id="isNotSunday",
name="Not Sunday",
expression="GetDayOfWeek(CurrentTime())",
operator=">",
value="0"
)
# Condition: GetDayOfWeek(CurrentTime()) < 6
end_of_week_condition = FlowNumericCondition(
id="isNotSaturday",
name="Not Saturday",
expression="GetDayOfWeek(CurrentTime())",
operator="<",
value="6"
)
# We need to combine these. Architect supports AND/OR in the flow structure.
# We will create a BooleanCondition that combines them.
boolean_condition = FlowBooleanCondition(
id="isWeekday",
name="Is Weekday",
expression="isNotSunday AND isNotSaturday",
# Note: The expression in BooleanCondition refers to the IDs of other conditions
# However, the API structure for BooleanCondition often requires the conditions to be listed.
# A more direct approach in the API is to use the 'conditions' array in the flow structure.
# Let's use a simpler approach: A single NumericCondition with a range is not directly supported
# by a single operator. We must use a BooleanCondition.
# Correct Structure for BooleanCondition in API:
# It does not take an "expression" string like the UI. It takes a list of conditions.
# But wait, the API model FlowBooleanCondition has 'conditions' and 'logic' (AND/OR).
conditions=[start_of_week_condition, end_of_week_condition],
logic="AND"
)
# Define the flow draft
flow_draft = FlowDraft(
name="Weekday Routing Flow",
description="Routes calls only on weekdays using GetDayOfWeek",
type="Inbound",
initial_action_id="startNode",
actions=[
FlowAction(
id="startNode",
name="Start",
action_type="Start",
# The start node has a 'default' path and 'conditions'
# We will attach the boolean condition here
conditions=[boolean_condition],
default_action=route_action
),
route_action
],
outbound_actions=[]
)
create_request = FlowCreateRequest(
draft=flow_draft
)
try:
response = flows_api.post_flow(body=create_request)
print(f"Flow created successfully: {response.id}")
return response
except ApiException as e:
print(f"Error creating flow: {e.status} - {e.reason}")
print(f"Response body: {e.body}")
raise
Correction on BooleanCondition Structure:
The FlowBooleanCondition model in the Python SDK maps to the JSON structure:
{
"id": "string",
"name": "string",
"conditions": [ ... ],
"logic": "AND" | "OR"
}
The conditions array contains references to other condition objects defined in the same flow.
Step 4: Using DateTimeDiff for Business Age
Now let us look at DateTimeDiff. Suppose we want to route calls to a priority queue if the contact has been waiting in the system for more than 5 minutes.
Expression: DateTimeDiff(CurrentTime(), Contact.QueueEntryDateTime, "minutes")
This expression calculates the difference in minutes between the current time and when the contact entered the queue.
We will add a second condition to our flow to demonstrate this.
from purecloud_platform_client.models import FlowNumericCondition
def add_priority_routing_condition():
"""
Creates a condition that checks if queue wait time > 5 minutes.
"""
priority_condition = FlowNumericCondition(
id="waitTimeCheck",
name="Wait Time > 5 Min",
expression='DateTimeDiff(CurrentTime(), Contact.QueueEntryDateTime, "minutes")',
operator=">",
value="5"
)
return priority_condition
To integrate this, we would modify the flow structure to include this condition in a decision node or as a secondary path. For brevity, we will update the previous flow creation function to include this logic in a more complex structure.
However, creating complex flows via API is verbose. Let us instead focus on validating the expression syntax using the Expression Validation endpoint, if available, or by attempting to create the flow and catching syntax errors.
Genesys Cloud does not have a dedicated “validate expression” endpoint that returns a boolean without side effects. The best practice is to create the flow in a draft state and check for validation errors.
Step 5: Complete Working Example with Error Handling
This script creates a flow with both GetDayOfWeek and DateTimeDiff logic. It handles common errors like invalid expression syntax.
import os
import json
from purecloud_platform_client import Configuration, PlatformClient
from purecloud_platform_client.rest import ApiException
from purecloud_platform_client.models import (
FlowCreateRequest,
FlowDraft,
FlowAction,
FlowRouteQueueAction,
FlowBooleanCondition,
FlowNumericCondition
)
def main():
# 1. Initialize Client
platform_client = init_platform_client()
# 2. Get Route Queue ID
# Replace with your actual queue ID or use the helper function
route_queue_id = "your-route-queue-id-here"
if route_queue_id == "your-route-queue-id-here":
print("Please provide a valid Route Queue ID.")
return
# 3. Define Conditions
# Condition A: Is Weekday?
# GetDayOfWeek returns 0 (Sun) to 6 (Sat)
# We want 1 (Mon) to 5 (Fri)
cond_not_sunday = FlowNumericCondition(
id="cond_not_sunday",
name="Not Sunday",
expression="GetDayOfWeek(CurrentTime())",
operator=">",
value="0"
)
cond_not_saturday = FlowNumericCondition(
id="cond_not_saturday",
name="Not Saturday",
expression="GetDayOfWeek(CurrentTime())",
operator="<",
value="6"
)
is_weekday_bool = FlowBooleanCondition(
id="cond_is_weekday",
name="Is Weekday",
conditions=[cond_not_sunday, cond_not_saturday],
logic="AND"
)
# Condition B: Wait Time > 5 Minutes
# Note: Contact.QueueEntryDateTime might be null if the contact has not been queued.
# In a real flow, you would handle nulls. For this example, we assume it exists.
cond_wait_time = FlowNumericCondition(
id="cond_wait_time",
name="Wait Time > 5 Min",
expression='DateTimeDiff(CurrentTime(), Contact.QueueEntryDateTime, "minutes")',
operator=">",
value="5"
)
# Combine into a final routing decision
# Route if Weekday AND (Wait Time > 5 or some other logic)
# For simplicity, let's just use the Weekday condition for the main path
# 4. Define Actions
route_action = FlowRouteQueueAction(
id="action_route",
name="Route to Queue",
route_queue_id=route_queue_id,
action_type="RouteQueue"
)
# 5. Define Flow Structure
# The Start action will evaluate the condition
start_action = FlowAction(
id="start",
name="Start",
action_type="Start",
conditions=[is_weekday_bool],
default_action=route_action
)
flow_draft = FlowDraft(
name="DevOps Test Flow - Date Logic",
description="Tests GetDayOfWeek and DateTimeDiff expressions",
type="Inbound",
initial_action_id="start",
actions=[start_action, route_action],
outbound_actions=[]
)
create_req = FlowCreateRequest(draft=flow_draft)
# 6. Create Flow
flows_api = platform_client.FlowsApi()
try:
flow = flows_api.post_flow(body=create_req)
print(f"Success: Flow created with ID {flow.id}")
print(f"Flow URL: {platform_client.configuration.host}/admin/#/flows/{flow.id}")
# 7. Cleanup (Optional): Delete the flow to avoid clutter
# flows_api.delete_flow(flow_id=flow.id)
# print("Flow deleted.")
except ApiException as e:
print(f"API Error: {e.status}")
print(f"Reason: {e.reason}")
# Parse error body for specific validation errors
if e.body:
try:
error_json = json.loads(e.body)
if 'errors' in error_json:
print("Validation Errors:")
for err in error_json['errors']:
print(f" - {err.get('message', 'Unknown error')}")
except:
print(f"Raw Body: {e.body}")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 400 Bad Request - Validation Failed
Cause: The expression syntax is incorrect, or a referenced condition ID does not exist.
How to Fix: Check the expression string for typos. Ensure GetDayOfWeek and DateTimeDiff are spelled correctly. Ensure the unit in DateTimeDiff is a valid string like "minutes", "hours", "days".
Code Fix: Verify the expression field in FlowNumericCondition.
# Incorrect
expression="GetDayOfWeek(CurrentTime()) > 0" # Operator is separate
# Correct
expression="GetDayOfWeek(CurrentTime())"
operator=">"
value="0"
Error: 400 Bad Request - Condition ID Not Found
Cause: A FlowBooleanCondition references condition IDs that are not present in the flow’s actions or conditions list.
How to Fix: Ensure all conditions referenced in the conditions array of a FlowBooleanCondition are defined in the flow’s action list or passed in the same request.
Code Fix: Make sure cond_not_sunday and cond_not_saturday are included in the flow structure.
Error: 429 Too Many Requests
Cause: Rate limiting due to rapid API calls.
How to Fix: Implement exponential backoff. The SDK does not automatically retry 429s in all versions.
Code Fix: Use a library like tenacity for retries.
from tenacity import retry, wait_exponential, stop_after_attempt
@retry(wait=wait_exponential(multiplier=1, min=4, max=10), stop=stop_after_attempt(5))
def create_flow_with_retry(flows_api, body):
return flows_api.post_flow(body=body)
Error: 500 Internal Server Error - Expression Evaluation Error
Cause: The expression is syntactically correct but fails at runtime (e.g., DateTimeDiff with null values).
How to Fix: In Architect, wrap expressions in IfNull checks. In the API, you can use the IfNull function in the expression.
Code Fix:
expression='IfNull(Contact.QueueEntryDateTime, CurrentTime())'