ColdFusion CreateTimeSpan() And CFLoop (via Ray Camden)

Posted June 18, 2009 at 2:29 PM by Ben Nadel

Tags: ColdFusion

I was just reading over on Ray Camden's blog about a user-submitted issue with the CFLoop behavior using times and a CreateTimeSpan()-based increment. Here is code equivalent to what Ray's reader submitted:

  • <!--- Create 5 minute interval step. --->
  • <cfset dtStep = CreateTimeSpan( 0, 0, 5, 0 ) />
  •  
  • <!--- Go from 9 AM to 10 AM every 5 minutes. --->
  • <cfloop
  • index="dtNow"
  • from="9 AM"
  • to="10 AM"
  • step="#dtStep#">
  •  
  • #TimeFormat( dtNow, "HH:mm" )#<br />
  •  
  • </cfloop>
  •  
  • <br />
  •  
  • <!--- Go from 10 AM to 11 AM every 5 minutes. --->
  • <cfloop
  • index="dtNow"
  • from="10 AM"
  • to="11 AM"
  • step="#dtStep#">
  •  
  • #TimeFormat( dtNow, "HH:mm" )#<br />
  •  
  • </cfloop>

Notice that we are looping from 9AM to 10AM and are using a Step value of 5 minutes as determined by ColdFusion's CreateTimeSpan() method. When we run the above code (and this was the same on Ray's blog), we get the following output:

09:00
09:05
09:10
09:15
09:20
09:25
09:30
09:35
09:40
09:45
09:50
09:55
10:00

10:00
10:05
10:10
10:15
10:20
10:25
10:30
10:35
10:40
10:45
10:50
10:55

Notice that the first loop runs 13 times, ending on the following hour, while the second loop runs only 12 times and ends on the 55 of the current hour.

So what's going on here? As Ray pointed out in his post, the value of the loop index becomes a floating point number - a number representation of the date. But, when I look at the above loop, you know what really sticks out at me in a huge way? The use of time values like "9 AM" and "10 AM". Something about this just seems really funky. I can't tell you why - it's just a gut feeling.

Acting on the gut feeling, I decided to make my From and To attributes a bit more explicit as far as time. Since we don't really care about the date, just the time, I'm going to define the From and To attributes in the same way that I'm defining my CFLoop step value - using CreateTimeSpan():

  • <!--- Create 5 minute interval step. --->
  • <cfset dtStep = CreateTimeSpan( 0, 0, 5, 0 ) />
  •  
  • <!--- Go from 9 AM to 10 AM every 5 minutes. --->
  • <cfloop
  • index="dtNow"
  • from="#CreateTimeSpan( 0, 9, 0, 0 )#"
  • to="#CreateTimeSpan( 0, 10, 0, 0 )#"
  • step="#dtStep#">
  •  
  • #TimeFormat( dtNow, "HH:mm" )#<br />
  •  
  • </cfloop>
  •  
  • <br />
  •  
  • <!--- Go from 10 AM to 11 AM every 5 minutes. --->
  • <cfloop
  • index="dtNow"
  • from="#CreateTimeSpan( 0, 10, 0, 0 )#"
  • to="#CreateTimeSpan( 0, 11, 0, 0 )#"
  • step="#dtStep#">
  •  
  • #TimeFormat( dtNow, "HH:mm" )#<br />
  •  
  • </cfloop>

This time, we aren't letting ColdFusion interpret "9AM" or "10AM" as a valid date/time stamp - we are telling it explicitly how to handle our numeric date representations. And, when we run this code, we get the following output:

09:00
09:05
09:10
09:15
09:20
09:25
09:30
09:35
09:40
09:45
09:50
09:55
10:00

10:00
10:05
10:10
10:15
10:20
10:25
10:30
10:35
10:40
10:45
10:50
10:55
11:00

Sweeet! This time, both CFLoops iterate 13 times and end on the following hour. This is the kind of behavior we want to see.

Having done this, I then got curious as to whether it was a numeric date representation issue, or if it was a string-to-date/time conversion issue. To test this, I ran another experiment, this time defining the From and To attributes using CreateTime(). CreateTime(), just like CreateDate(), does not create a numeric date, but rather a standard ColdFusion date/time stamp based off of the ColdFusion "zero date":

CreateTime( 9, 0, 0 ) == {ts '1899-12-30 09:00:00'}

As you can see, CreateTime() creates a valid date/time stamp (just like Now() or ParseDateTime()). I put this into the CFLoop attributes:

  • <!--- Create 5 minute interval step. --->
  • <cfset dtStep = CreateTimeSpan( 0, 0, 5, 0 ) />
  •  
  • <!--- Go from 9 AM to 10 AM every 5 minutes. --->
  • <cfloop
  • index="dtNow"
  • from="#CreateTime( 9, 0, 0 )#"
  • to="#CreateTime( 10, 0, 0 )#"
  • step="#dtStep#">
  •  
  • #TimeFormat( dtNow, "HH:mm" )#<br />
  •  
  • </cfloop>
  •  
  • <br />
  •  
  • <!--- Go from 10 AM to 11 AM every 5 minutes. --->
  • <cfloop
  • index="dtNow"
  • from="#CreateTime( 10, 0, 0 )#"
  • to="#CreateTime( 11, 0, 0 )#"
  • step="#dtStep#">
  •  
  • #TimeFormat( dtNow, "HH:mm" )#<br />
  •  
  • </cfloop>

When we run this code, we get the following output:

09:00
09:05
09:10
09:15
09:20
09:25
09:30
09:35
09:40
09:45
09:50
09:55
10:00

10:00
10:05
10:10
10:15
10:20
10:25
10:30
10:35
10:40
10:45
10:50
10:55

Interesting! This methodology fails in the same was as our first methodology (using values like "9AM").

So, what does this mean? We can conclude that the issue is not in how ColdFusion converts a date/time string into a date/time stamp; rather, the issue is in how ColdFusion converts a date/time stamp into a numeric date representation. To get around this, we have two choices: either, we modify the CFLoop to use DateAdd() as Ray pointed out in his blog post; or, if we want to use CreateTimeSpan() for our increment, we must make sure to define all of our limits using CreateTimeSpan().




Reader Comments

Jun 18, 2009 at 11:17 PM // reply »
32 Comments

Wow, some good timely info to know! I just finished working on an application that is looping over times of the day like this. I'll have to check my application to see if this error is possible when times are defined as "10:00 AM" and "11:00 AM" which is how I'm using the cfloop rather than "10 AM" and "11 AM".


Jun 19, 2009 at 9:13 AM // reply »
10,638 Comments

@CoolJJ,

Nice - right place, right time :)


Aug 3, 2009 at 11:30 AM // reply »
6 Comments

Hi Ben,

I want create a script to generate a calendar for a soccer tournament.

I think I should use cfloop to create single event for every team, but also a cfloop to create x match for x event, because the team are from 20 to 40.

What about cfloop timeout?


Aug 3, 2009 at 10:53 PM // reply »
6 Comments

Hi ben,

I was trying to develop a little script with Berger's algorithm to create a calendar for a championship...

this is my code, but I get errors...

<cfset names = ArrayNew(1) />
<cfset names[1] = "Napoli" />
<cfset names[2] = "Milan" />
<cfset names[3] = "Inter" />
<cfset names[4] = "Juve" />
<cfset names[5] = "Samp" />
<cfset names[6] = "Genoa" />
<cfset teams = ArrayLen(#names#) />
<cfset totalrounds = #teams# - 1 />
<cfset matchesxround = #teams# / 2 />

<cfloop index="round" from="0" to="#totalrounds#" step="1">
<cfloop index="match" from="0" to="#matchesxround#">
<cfset home = (#round# + #match#) % (#teams# - 1) />
<cfset away = (#teams# - 1 - #match#) % (#teams# - 1) />
<cfif #match# Eq 0 >
<cfset away = #teams# - 1 />
</cfif>
<cfset num = #home# + 1 />
<cfset names = #away# + 1 />
<cfinvoke component="utlity" method="teamname">
<cfinvokeargument name="num" value="#num#">
<cfinvokeargument name="names" value="#names#">
</cfinvoke>
</cfloop>
</cfloop>

<cfoutput>
TEAMS:#teams#<br />
HOME:#home#<br />
#ArrayToList(names)#<br />
#ArrayLen(names)#<br />
</cfoutput>

Could you help me?


Aug 5, 2009 at 8:59 AM // reply »
10,638 Comments

@Francesco,

As a side note, you need almost none of those "#" signs. You only need a "#" when you are evaluating a ColdFusion variable inside a string. All other areas of use are unnecessary.

That said, I cannot run this as I don't have the "utility" component. But, from what I've seen, you are changing the names variable. Do you mean to do that? At first you have "names" as an array. Then, later on you have:

<cfset names = #away# + 1 />

... this will convert the "names" variable into a number.

I'm guessing that was not intended?


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »