tags:

views:

256

answers:

3

Given that a certain business is open 8am-5pm, what is the best way to verify that a given timespan falls within that range? The date doesn't matter, just need to confirm that the entire requested time range falls within business hours.

Here is my sample data I have to begin with. (I'm using cfscript here simply to be concise)

<cfscript>
    // array of given timeslots to test
    timeslots = arrayNew(1);

    // 1st appointment, entirely within normal business hours
    appointment = structNew();
    appointment.begin = "10:00 AM";
    appointment.end = "2:00 PM";

    arrayAppend(timeslots, appointment);

    // 2nd appointment, outside of normal business hours
    appointment = structNew();
    appointment.begin = "7:00 PM";
    appointment.end = "9:00 PM";

    arrayAppend(timeslots, appointment);

    // 3rd appointment, kind of tricky, partly within business hours, still should fail
    appointment = structNew();
    appointment.begin = "3:00 PM";
    appointment.end = "6:00 PM";

    arrayAppend(timeslots, appointment);

    </cfscript>

Now, I'll loop over that array run a validation function on each struct. For the sake of example, it could look like this:

<cfoutput>
<cfloop array="#timeslots#" index="i">
    <!--- Should return 'true' or 'false' for each item --->
    #myValidator(i.begin, i.end)#<br />
</cfloop>
</cfoutput>

...So back to the real question,... how do I use Coldfusion to compare those times with the given business hours?

<cfscript>
// if input data is outside of the internal time range, return false, otherwise true
function myValidator(begin, end) {
    var businessStart = "8:00 AM";
    var businessEnd = "5:00 PM";
    var result = false;

    // what kind of tests do I put here to compare the times?
}
</cfscript>

UPDATE: my solution - rewrite of myValidator from above based on the feedback of Ben Doom and kevink.

// checks if any scheduled events fall outside business hours
function duringBusinessHours(startTime, endTime) {
    var result = true;
    var busStart = 800;
    var busEnd = 1700;
    var startNum = 0;
    var endNum = 0;

    // convert time string into a simple number:
    // "7:00 AM" -> 700 | "3:00 PM" -> 1500
    startNum = timeFormat(arguments.startTime, "Hmm");
    endNum = timeFormat(arguments.endTime, "Hmm");

    // start time must be smaller than end time
    if (startNum GTE endNum) {
       result = false;

    // If start time is outside of business hours, fail
    } else if (startNum LT busStart OR startNum GT busEnd) {
       result = false;  

    // If end time is outside of business hours, fail
    } else if (endNum LT busStart OR endNum GT busEnd) {
       result = false;
    }
    return result;
}
+1  A: 

Personally I would created two date objects using CreateDateTime with same m/d/y values and compared them, since CF can do this correctly.

Sergii
You mean 4 date objects right? two for the incoming times to compare and two for the existing business hours.Hmmm..... I was figuring as much. It just seems there should be an elegant way to test timespans against other timespans.
Dan Sorensen
I don't think converting to datetimes is inelegant. If you want to make your compare code cleaner, you could always roll your own eventspan cfc (I'd avoid calling it timespan, fearing confusion with createtimespan()). But, in the end, you'd probably just be hiding the code in an abstraction layer, and if this is the only thing you buy, I'd skip it.
Ben Doom
I don't think this logic warrants its own cfc, but it would probably be useful to create a UDF along the lines of timeSpanCollision(testStartTime, testEndTime, existingStartTime, existingEndTime, "overlap|collide"). Overlap would be a full overlap, whereas collide would only partially overlap.
Dan Sorensen
+1  A: 

If you don't care about days use a 24 hour clock, treat everything as a simple number and just use greater than, less than...

 <cfif arguments.startime LT bizStart OR arguments.endtime GT bizEnd>
   <cfreturn false>
 <cfelse>
   <cfreturn true>
 </cfif>
kevink
You may want to check to make sure that the end time is after the begin time. Otherwise, you could begin after close (also after open) and end before open (also after close). Overnight events should fail.
Ben Doom
@Ben: Good points.@Kevin: I updated my example above with my solution using your line of thinking.
Dan Sorensen
A: 

You definitely want to create a date/time object with CreateDateTime and then compare dates/time frames that way. If you are taken input as a string from a webpage you can use ParseDateTime to convert a string representing a valid date/time format to a date/time object.

Cody Caughlan
During testing, since I only have a simple time string. I found that it took longer to turn a time string into a full datetime object and perform the calculation using dateCompare(timeA, timeB, "n") than to use timeFormat(timeString, "Hmm") and convert to a regular number that could be compared with GT and LT.
Dan Sorensen
However, I was using createDateTime() which was cumbersome. I totally forgot about ParseDateTime() which would have been more ideal for this purpose.
Dan Sorensen