cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
14445
Views
71
Helpful
20
Replies

UCCX 9 "Time of Day" Time Ranges

nkobayashi123
Level 1
Level 1

Good afternoon everyone

I have a question about Time of Day's time range.   Will it be possible to change time range to 10 minutes or 5 minutes ?   (instead of 15min increment)

One of my customers is requesting her call center to stop accepting calls at 4:20 pm.  (4:15 pm is too early and 4:30 pm is too late for her...)     So,  basically, she needs incoming calls to be coming to her call center queue till 4:20pm.   Her call center agents will answers calls in queue till they are all taken care.  If a customer calls at 4:19pm, the call will go to queue and wait for next available agent.   If a customer calls at 4:21 pm, it goes to closed message... 

(I've suggested her if the agents can log out after 4:20pm but that was not the option...)

If you have any suggestions, please let me know. I really appreciate your help and support 

Thank you,

Nana

2 Accepted Solutions

Accepted Solutions

Anthony Holloway
Cisco Employee
Cisco Employee

You cannot do this with the built-in Time of Day step.

You can do this with a Time object and an If step.

If (T[now].after(T[4:20 PM]))

     True

          /* It's now after 4:20pm */

     False

          /* It's before 4:20pm */

Note that milliseconds are considered here.  So, 4:20:00.000 is what is implied by T[4:20 PM], and therefore the Time.after() method will return true for 4:20:00.001 PM and beyond.

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

View solution in original post

Now you can offer to-the-millisecond opening and closing of call centers.  No more 15 minute intervals!

For the sake of completeness, someone might see this thread and wonder two things:

  1. How do I specify a TimeZone like I can with the Time of Day step?
  2. How do I create different time ranges like I can with the Time of Day step?

Here are my responses to each.

1. TimeZone Support

Currently Cisco does not have a way to instantiate a dynamic Time object while specifying the TimeZone.  What does that mean exactly?  Well, let's take a closer look at the example I gave earlier:

If (T[now].after(T[4:20 PM]))

     True

          /* It's now after 4:20pm */

     False

          /* It's before 4:20pm */

This is a single step: If.  The condition or expression it is evaluating is as follows:

T[now].after(T[4:20 PM])

This condition has two Time objects and one method call.

Time Object 1

T[now]

This Time object has been created with the "now" keyword, which tells UCCX to create the object with the current time on the server, in the primary servers TimeZone.  The primary server being Node 1, or the Publisher Node, however you like to think of it.  So, its TimeZone setting, as configured during installation.

If UCCX were to execute this command at 4:20 PM and the server timezone is CST, then this value becomes 4:20:00.000 PM CST.

Time Object 2

T[4:20 PM]

This Time object is like the one described above with one exception: I am telling the system what time to use.  This Time object will still use the Primary server's time zone, and thus becomes: 4:20:00.000 PM CST.

Time Object Method Call 1

.after()

This method allows you to test boolean logic to see if the Time on the left, is after the Time inside the parenthesis.

Here are a few example tests to help your understanding:

T[10:00 AM].after(T[9:00 AM]) == True

T[11:00 PM].after(T[3:00 PM]) == True

T[12:00 AM].after(T[6:00 AM]) == False

T[5:15 PM].after(T[5:00 PM]) == True

Now that we've broken down the example, and we know that the TimeZone object inherits the TimeZone from the Primary server, let's see how we can change the TimeZone.  If you were to look at the documented format for Time literals (T[???]), you will see that there is support for T[??? CST].  However, this only applies to you when using a time value like: 4:20 PM, and not when you're using the "now" keyword.

Right

T[4:20 PM CST]

Wrong

T[now CST]

The documentation (the programming guides) do not tell you about this next trick, however, it can be seen in the expression editor as a quick button for building formulas.  It uses a TimeZone literal, and these are only available from version 8x+.  However, these too are only for literal time values, and not the "now" keyword.

Right

T[4:20 PM, TZ[America/Chicago]]

Wrong

T[now, TZ[America/Chicago]]

I've found a trick that we can use to get the second example to work with the "now" keyword.  Two things: 1) there are many different ways to set or change the TimeZone, this is not the only way, and 2) Cisco is aware and are addressing this limitation with the "now" keyword.

The "now" Trick

D[D[now], TZ[America/Chicago]]

This only works with Date objects for some reason, but fear not, the Date object has both the Date and Time in it.

The reason this works is because the inner D[now] is turned into it's representation of the date, which D[???] can understand, and then because we are now using the value from D[now], the D[???, TZ[???]] format works as if we typed the value in ourselves.

This is how we turn that into a Time object, so we can get back to working with Times:

my_time = new Time(D[D[now], TZ[America/Chicago]].getTime())

How does this change our if step to support timezones?

If (new Time(D[D[now], TZ[America/Chicago]].getTime()).after(T[4:20 PM, TZ[America/Chicago]]))

     True

          /* It's now after 4:20pm */

     False

          /* It's before 4:20pm */

It's a bit long and complicated looking.  One way to solve that is to use some variables:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time closing_time = T[4:20 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(closing_time))

     True

          /* We're closed */

     False

          /* We're open */

...

The key thing in the above script is that you cannot nest final variables, which makes using the following method invalid, but would have been nice:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

final Date today = D[D[now], target_timezone]

Time current_time = new Time(today.getTime())

Time closing_time = T[4:20 PM, target_timezone]

So we had to resort to placing a Set step within the script to evaluate the current time value.  That's not all bad; it's just one step.  And I placed the Set step above the Accept step because I wanted it to be evaluated as close to when the call starts as possible.

And that's working with TimeZone support.

2. Time Ranges

The above was dealing with a simple "is it past X time?" conditional logic.  What if you wanted to ask the system if the current time was in between two times?

We'll keep things looking familiar for this next part, but do keep in mind that there are other ways to accomplish this task, this is just one of them.

Say we wanted to know if we're open or not, and our business hours are 8:00am - 5:00pm (we'll skip on day of week for now and pretend we're open the same time everyday).

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time opening_time = T[8:00 AM, target_timezone]

Time closing_time = T[5:00 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(opening_time) && current_time.before(closing_time))

     True

          /* We're Open */

     False

          /* We're Closed */

...

That should look pretty straight forward to you.  I think this is how most people are using business hours logic: a single time window during the day.  I hope it also reads very easily as "If the current time is after our opening time and the current time is also before our closing time, then we're open, otherwise we're closed."

Don't forget that Time objects go down to the millisecond, so even though I am asking if it's "after" and "before" as opposed to "on or after" and "on or before", we're talking the difference of 1000th of a second.  To me that's nothing to worry about.

Let's step it up one level and work with three different time ranges (normal business hours, pre-closing hours, and closed hours).  I have seen before, a call center partially shutdown during non-busy time periods and offer limited services, or staff minimally during these periods.

Let's see what it looks like:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time opening_time = T[8:00 AM, target_timezone]

Time partial_time = T[5:00 PM, target_timezone]

Time closing_time = T[8:00 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(closing_time))

     True

          Goto Closed

     False

If (current_time.after(partitial_time))

     True

          Goto Partially Open

     False

If (current_time.after(opening_time))

     True

          Goto Open

     False

Closed:

...

Partially Open:

...

Open:

...

I don't really enjoy nesting too many steps, so I leverage the Goto steps and the script's natural behavior to cascade its way through the script for this particular solution.  This solution is relying on a bit of implied logic here. For example, I don't have to check if the current time is between partial and closed to know if we're in partial, because that If step for partial would only ever be executed if we were not closed.  It's implied that we're not closed.

If that's too confusing, here is an alternate way to do the same as the above, but with explicitly defining the conditionals:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time opening_time = T[8:00 AM, target_timezone]

Time partial_time = T[5:00 PM, target_timezone]

Time closing_time = T[8:00 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(opening_time) && current_time.before(closing_time))

     True

          If (current_time.before(partitial_time))

               True

                    Goto Open

               False

                    Goto Partially Open

     False

Closed:
...
Partially Open:
...
Open:

...

I hope that helped and didn't add too much confusion.  Happy scripting!

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

View solution in original post

20 Replies 20

Anthony Holloway
Cisco Employee
Cisco Employee

You cannot do this with the built-in Time of Day step.

You can do this with a Time object and an If step.

If (T[now].after(T[4:20 PM]))

     True

          /* It's now after 4:20pm */

     False

          /* It's before 4:20pm */

Note that milliseconds are considered here.  So, 4:20:00.000 is what is implied by T[4:20 PM], and therefore the Time.after() method will return true for 4:20:00.001 PM and beyond.

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

OMG!!!   Thank YOU!!!  It works PERFECTLY!!!!!    Thank YOU.  This works great for many call centers now!!!!!

Nana

Now you can offer to-the-millisecond opening and closing of call centers.  No more 15 minute intervals!

For the sake of completeness, someone might see this thread and wonder two things:

  1. How do I specify a TimeZone like I can with the Time of Day step?
  2. How do I create different time ranges like I can with the Time of Day step?

Here are my responses to each.

1. TimeZone Support

Currently Cisco does not have a way to instantiate a dynamic Time object while specifying the TimeZone.  What does that mean exactly?  Well, let's take a closer look at the example I gave earlier:

If (T[now].after(T[4:20 PM]))

     True

          /* It's now after 4:20pm */

     False

          /* It's before 4:20pm */

This is a single step: If.  The condition or expression it is evaluating is as follows:

T[now].after(T[4:20 PM])

This condition has two Time objects and one method call.

Time Object 1

T[now]

This Time object has been created with the "now" keyword, which tells UCCX to create the object with the current time on the server, in the primary servers TimeZone.  The primary server being Node 1, or the Publisher Node, however you like to think of it.  So, its TimeZone setting, as configured during installation.

If UCCX were to execute this command at 4:20 PM and the server timezone is CST, then this value becomes 4:20:00.000 PM CST.

Time Object 2

T[4:20 PM]

This Time object is like the one described above with one exception: I am telling the system what time to use.  This Time object will still use the Primary server's time zone, and thus becomes: 4:20:00.000 PM CST.

Time Object Method Call 1

.after()

This method allows you to test boolean logic to see if the Time on the left, is after the Time inside the parenthesis.

Here are a few example tests to help your understanding:

T[10:00 AM].after(T[9:00 AM]) == True

T[11:00 PM].after(T[3:00 PM]) == True

T[12:00 AM].after(T[6:00 AM]) == False

T[5:15 PM].after(T[5:00 PM]) == True

Now that we've broken down the example, and we know that the TimeZone object inherits the TimeZone from the Primary server, let's see how we can change the TimeZone.  If you were to look at the documented format for Time literals (T[???]), you will see that there is support for T[??? CST].  However, this only applies to you when using a time value like: 4:20 PM, and not when you're using the "now" keyword.

Right

T[4:20 PM CST]

Wrong

T[now CST]

The documentation (the programming guides) do not tell you about this next trick, however, it can be seen in the expression editor as a quick button for building formulas.  It uses a TimeZone literal, and these are only available from version 8x+.  However, these too are only for literal time values, and not the "now" keyword.

Right

T[4:20 PM, TZ[America/Chicago]]

Wrong

T[now, TZ[America/Chicago]]

I've found a trick that we can use to get the second example to work with the "now" keyword.  Two things: 1) there are many different ways to set or change the TimeZone, this is not the only way, and 2) Cisco is aware and are addressing this limitation with the "now" keyword.

The "now" Trick

D[D[now], TZ[America/Chicago]]

This only works with Date objects for some reason, but fear not, the Date object has both the Date and Time in it.

The reason this works is because the inner D[now] is turned into it's representation of the date, which D[???] can understand, and then because we are now using the value from D[now], the D[???, TZ[???]] format works as if we typed the value in ourselves.

This is how we turn that into a Time object, so we can get back to working with Times:

my_time = new Time(D[D[now], TZ[America/Chicago]].getTime())

How does this change our if step to support timezones?

If (new Time(D[D[now], TZ[America/Chicago]].getTime()).after(T[4:20 PM, TZ[America/Chicago]]))

     True

          /* It's now after 4:20pm */

     False

          /* It's before 4:20pm */

It's a bit long and complicated looking.  One way to solve that is to use some variables:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time closing_time = T[4:20 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(closing_time))

     True

          /* We're closed */

     False

          /* We're open */

...

The key thing in the above script is that you cannot nest final variables, which makes using the following method invalid, but would have been nice:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

final Date today = D[D[now], target_timezone]

Time current_time = new Time(today.getTime())

Time closing_time = T[4:20 PM, target_timezone]

So we had to resort to placing a Set step within the script to evaluate the current time value.  That's not all bad; it's just one step.  And I placed the Set step above the Accept step because I wanted it to be evaluated as close to when the call starts as possible.

And that's working with TimeZone support.

2. Time Ranges

The above was dealing with a simple "is it past X time?" conditional logic.  What if you wanted to ask the system if the current time was in between two times?

We'll keep things looking familiar for this next part, but do keep in mind that there are other ways to accomplish this task, this is just one of them.

Say we wanted to know if we're open or not, and our business hours are 8:00am - 5:00pm (we'll skip on day of week for now and pretend we're open the same time everyday).

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time opening_time = T[8:00 AM, target_timezone]

Time closing_time = T[5:00 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(opening_time) && current_time.before(closing_time))

     True

          /* We're Open */

     False

          /* We're Closed */

...

That should look pretty straight forward to you.  I think this is how most people are using business hours logic: a single time window during the day.  I hope it also reads very easily as "If the current time is after our opening time and the current time is also before our closing time, then we're open, otherwise we're closed."

Don't forget that Time objects go down to the millisecond, so even though I am asking if it's "after" and "before" as opposed to "on or after" and "on or before", we're talking the difference of 1000th of a second.  To me that's nothing to worry about.

Let's step it up one level and work with three different time ranges (normal business hours, pre-closing hours, and closed hours).  I have seen before, a call center partially shutdown during non-busy time periods and offer limited services, or staff minimally during these periods.

Let's see what it looks like:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time opening_time = T[8:00 AM, target_timezone]

Time partial_time = T[5:00 PM, target_timezone]

Time closing_time = T[8:00 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(closing_time))

     True

          Goto Closed

     False

If (current_time.after(partitial_time))

     True

          Goto Partially Open

     False

If (current_time.after(opening_time))

     True

          Goto Open

     False

Closed:

...

Partially Open:

...

Open:

...

I don't really enjoy nesting too many steps, so I leverage the Goto steps and the script's natural behavior to cascade its way through the script for this particular solution.  This solution is relying on a bit of implied logic here. For example, I don't have to check if the current time is between partial and closed to know if we're in partial, because that If step for partial would only ever be executed if we were not closed.  It's implied that we're not closed.

If that's too confusing, here is an alternate way to do the same as the above, but with explicitly defining the conditionals:

Variables

final TimeZone target_timezone = TZ[America/Chicago]

Date today = D[D[now], target_timezone]

Time current_time = null

Time opening_time = T[8:00 AM, target_timezone]

Time partial_time = T[5:00 PM, target_timezone]

Time closing_time = T[8:00 PM, target_timezone]

Script

Start

Set current_time = new Time(today.getTime())

Accept (--Triggering Contact--)

...

If (current_time.after(opening_time) && current_time.before(closing_time))

     True

          If (current_time.before(partitial_time))

               True

                    Goto Open

               False

                    Goto Partially Open

     False

Closed:
...
Partially Open:
...
Open:

...

I hope that helped and didn't add too much confusion.  Happy scripting!

Anthony Holloway

Please use the star ratings to help drive great content to the top of searches.

WOW again!!!  Nice!!!   Thank you and I'm sure many people are thanking you too

Nana

Superb...

 

Great Post 

 

Thank you very much 

Regds

$

Thanks for replying!  I'm happy you found it helpful.

Any idea why this statement:

my_time = new Time(D[D[now], TZ[America/Chicago]].getTime())

would ignore the time zone on my 10.6.1 UCCX server?  I.e. my primary UCCX server is in America/New_York, and the New York time zone is used even though I hard code the America/Chicago exactly as your example has it.

Could this be a licensing issue?  I see that https://supportforums.cisco.com/discussion/11851751/how-make-uccx-holiday-script-timezone-aware mentions having a premium license, which I don't have.

Interestingly, I took a look and I don't see how it ever worked.  I might have had a flaw in my testing, in that my server timezone might have been America/Chicago.  See, getTime() is in GMT, and has not timezone awareness, so I don't see how my posted solution would have ever worked.

I can't believe you'd ever make a mistake!  :) However even if that example is flawed I can't even get this example to work:

T[4:20 PM, TZ[America/Chicago]]

When I debug it America/Chicago is always replaced with America/New_York.  Working with dates the time zone works as expected, but I haven't been able to find a way to make a time object work with a time zone I supply.

Yeah, the D[?, ?] and T[?, ?] are flawed.

I'm attaching a script I worked on a while back, which works as a subflow, calculating if the current time is between a given pair of times: start and end.  You simply pass it three arguments:  start, end, and optionally timezone.

I created it to overcome the short comings and frustration one experiences when working with Date and Time classes in Cisco's Expression Language.

Thanks for sharing your subflow, I may use it in the future. However while your subflow is probably the best and simplest way to solve this problem with Java, I decided to go with built in UCCX commands to make it easier for those not familiar with Java to maintain.  When I learned from your most excellent post above that time variables are not time zone aware I initially thought this was an oversight/shortcoming.  However, after thinking about this some more I actually think that this was probably an intentional design decision, since it doesn't make sense to use time zones with a variable that is not date aware.

For example does 12:30 AM come before 7 AM? Of course, unless you're referring to 12:30 AM ET and 7:30 AM CT. Then which comes first?  It depends on the date (since 12:30 AM ET is 11:30 PM CT the day prior).  Since time variables don't contain a date you really can't compare two time variables with time zones.  I.e. time variables are only useful when both time variables are in the same time zone.

Since time variables are just a subset of date variables I believe the best non-Java UCCX solution is to simply not use time variables and use date variables instead (which are time zone aware).  For example this is how I check two times that may have different time zones:

Set timeToCheck_date = D[now] //This is eastern time in my case
Set todaysDate_str = D[now] //gets set to something like "2/8/2017"
Set timeZone_tz = "America/Chicago"
Set startTime_str = "4:00 PM"
Set startTime_date = D[todaysDate_str + " " + startTime_str, timeZone_tz]
If timeToCheck_date.after(startTime_date)
    True = timeToCheck occurs after the startTime
    False = timeToCheck occurs before the startTime

TomMar1
Level 3
Level 3

Old thread, I know but good details here and I think this starts me in the right direction.

Here is what I am looking to accomplish.  I am sending an email based on the number of calls in queue, however I do not want to send an email every time that condition occurs, only the first time and then again only after 15 minutes has passed and the condition persists/occurs.  I am just not sure of the logic to do that.  I need a way to compare the current time with the time the last email was sent.

Scripting beginner here, so forgive me in advance.

Thanks

If you know how long each loop through the queue takes you could simply use a variable of the type integer and increment it each loop. Then when the variable reach the value that equals the time you want to wait between emails you can send the email again. To evaluate this you would use an if statement.



Response Signature


My concern would be that every additional over queue threshold call would trigger the email as opposed to one email when the queue threshold is exceeded and none until the queue threshold is exceeded and 15 minutes has expired.  Working through this with you I realize that each call session that was over the queue threshold would trigger an email. 

So there would need to be a variable that could carry over between call sessions, not sure that is possible.

 

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: