Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with:

Getting A Random Date Between Two Given Dates In ColdFusion

By Ben Nadel on
Tags: ColdFusion

Over the weekend, I came up against the ColdFusion task of selecting a random date between two given dates. In the past, I have created a ColdFusion user defined function, RandDateRange( dtFrom, dtTo ), and I thought this would be a perfect time to apply it. After reviewing that one though, I see that it not only randomizes the date but also the time by selecting a random mid point in seconds between the two dates.

Well, what happens when I don't want to include a random time? I suppose that I could just Fix() the value that gets returned. But what fun would that be? I had some time on my hands, so I figured I would update the RandDateRange() function to handle date-only values as well.

This modified ColdFusion UDF takes two dates and a flag for randomization of time. If both dates are integer values (they have no time parts) then the function randomizes the date only unless the time randomization flag is sent as true. If either of the passed-in dates includes a time part, then time is also randomized. In addition, this update also formats the returned values. The previous version of the UDF passed back numeric values for the date. This works fine, if you know what's going on, but this returned value will fail IsDate() calls. And, unless you know to use IsNumericDate() calls, you might be lost.

  • <cffunction
  • name="RandDateRange"
  • access="public"
  • returntype="date"
  • output="false"
  • hint="Returns a random date between the two passed in dates. If either of the two dates has a time value, the resultant time will also be randomized.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="DateFrom"
  • type="date"
  • required="true"
  • hint="The min date of the date range."
  • />
  •  
  • <cfargument
  • name="DateTo"
  • type="date"
  • required="true"
  • hint="The max date of the date range."
  • />
  •  
  • <cfargument
  • name="IncludeRandomTime"
  • type="boolean"
  • required="false"
  • default="false"
  • hint="Will include the time in the date randomization even if neither passed-in dates have a time."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = StructNew() />
  •  
  •  
  • <!---
  • Check to see if we are going to randomize time.
  • If either of the passed in dates has a non-12 AM
  • time, then we are going to include a random time.
  • We will know if a date is include if the either
  • date does not equal its Fixed value.
  • --->
  • <cfif (
  • (ARGUMENTS.DateFrom NEQ Fix( ARGUMENTS.DateFrom )) OR
  • (ARGUMENTS.DateTo NEQ Fix( ARGUMENTS.DateTo )) OR
  • ARGUMENTS.IncludeRandomTime
  • )>
  •  
  • <!---
  • Get the difference in seconds between the two
  • given dates. Once we have this value, we can
  • pick a random mid point in this span of seconds.
  • --->
  • <cfset LOCAL.DiffSeconds = DateDiff(
  • "s",
  • ARGUMENTS.DateFrom,
  • ARGUMENTS.DateTo
  • ) />
  •  
  • <!---
  • Now that we know the second difference between the
  • two dates, we can easily use RandRange() to get a
  • random second span that we will add to the start
  • date to give us a random mid date.
  • --->
  • <cfset LOCAL.Date = (
  • ARGUMENTS.DateFrom +
  • CreateTimeSpan(
  • 0, <!--- Days. --->
  • 0, <!--- Hours. --->
  • 0, <!--- Minutes --->
  •  
  • <!---
  • Now, let's pick the random number of
  • seconds for this added time span.
  • --->
  • RandRange(
  • 0,
  • LOCAL.DiffSeconds
  • )
  • )
  • ) />
  •  
  • <!---
  • Now that we have the randome date/time value, we
  • need to format it using both the date and the time.
  • We cannot just send back the DateFormat() (as in the
  • other case) since that would strip out the time.
  • --->
  • <cfreturn
  • DateFormat( LOCAL.Date ) & " " &
  • TimeFormat( LOCAL.Date )
  • />
  •  
  • <cfelse>
  •  
  • <!---
  • We are not going to include a random time.
  • Therefore, we can just get a random integer
  • to represent the date (no time). Since date/time
  • values can be represented as float values, we
  • can just use RandRange() to get a random
  • integer which we will then convert back to a
  • date/time value. DateFormat() will convert it back
  • to a date value with zero time.
  • --->
  • <cfreturn
  • DateFormat(
  • RandRange(
  • ARGUMENTS.DateFrom,
  • ARGUMENTS.DateTo
  • )
  • )
  • />
  •  
  • </cfif>
  • </cffunction>

Notice that we are calling DateFormat() for the date-only randomization and DateFormat() and TimeFormat() for the date/time randomization. This will result in a true date value that will return TRUE when passed to IsDate().

In this test, we are going to select JUST the date value between two given dates:

  • <!--- Select 5 random dates. --->
  • <cfloop
  • index="intI"
  • from="1"
  • to="5"
  • step="1">
  •  
  •  
  • <!---
  • Get the random date. Since these values do not include
  • time, this will only select random dates with no time.
  • --->
  • <cfset dtRandDate = RandDateRange(
  • "05/01/2007",
  • "05/20/2007"
  • ) />
  •  
  • <!--- Output the date. --->
  • #dtRandDate#<br />
  •  
  • </cfloop>

This gives us the output:

19-May-07
20-May-07
16-May-07
01-May-07
10-May-07

Now, let's run that same thing, except this time, let's pass through the flag for additional time randomization.

  • <!--- Select 5 random dates. --->
  • <cfloop
  • index="intI"
  • from="1"
  • to="5"
  • step="1">
  •  
  •  
  • <!---
  • Get the random date. Since these values do not include
  • time, they should only return random dates. However,
  • since we are passing in the flag for time randomization,
  • then this will select random dates and times.
  • --->
  • <cfset dtRandDate = RandDateRange(
  • "05/01/2007",
  • "05/20/2007",
  • true
  • ) />
  •  
  • <!--- Output the date. --->
  • #dtRandDate#<br />
  •  
  • </cfloop>

This gives us the output:

15-May-07 05:36 PM
10-May-07 04:41 AM
14-May-07 01:34 PM
18-May-07 06:23 AM
07-May-07 10:03 PM

Works like a charm, and notice that the values getting returned don't even have to be formatted - they are true dates (in string format).

Now, just one final test to demonstrate that when one of the dates has a time portion, the randomized date also has a time portion:

  • <!--- Select 5 random dates. --->
  • <cfloop
  • index="intI"
  • from="1"
  • to="5"
  • step="1">
  •  
  •  
  • <!---
  • Get the random date. Since at least one of these
  • passed-in date values has a time portion, then the
  • UDF will automatically use time randomization even
  • though no flag was sent.
  • --->
  • <cfset dtRandDate = RandDateRange(
  • "05/01/2007 10:00 AM",
  • "05/01/2007 05:00 PM"
  • ) />
  •  
  • <!--- Output the date. --->
  • #dtRandDate#<br />
  •  
  • </cfloop>

Running the above we get:

01-May-07 12:32 PM
01-May-07 10:48 AM
01-May-07 03:13 PM
01-May-07 01:34 PM
01-May-07 11:41 AM

I think this is a good update to the previous RandDateRange() ColdFusion user defined function.



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

I enjoy this code. But for what reasons I will need this function? I don't find practical implementation

Reply to this Comment

Yeah, true, not a ton of practical uses. To be honest, I am not sure why I even tried to do this. I know I had a task in mind, but cannot recall it.

Looks like someone is having a case of the Mondays :)

Reply to this Comment

Yeah, when I get stuck on a problem, or I get an idea that I want to work on, I try to explore different aspects of it - see what I missed or I don't understand. I even try to tackle old problems sometimes to see if the time since they were first solved has shed light on better ways of doing things.

Plus, sometimes there's nothing good on the 2 TV channels that I get via my antenna :)

Reply to this Comment

You should consider using including a calendar table in your database- it makes life a whole lot easier! Just creating a simple table containing the date, whether is is a weekday, the year, quarter, month, day, day of week, month name, dayname, week number, holiday, etc. makes picking random days or doing certain types of reporting a snap. Plus you are putting the work on the db server, not on the application server.... if you google "TSQL calendar table" you should find some examples.

Reply to this Comment

@Bob,

What you said got me thinking... not necessarily about this post, but about calendars in general. I think it would be awesome to store additional "info" columns about the date. Things like day of the week (1-7) or like "is_last_day", or "is_first_monday"... things like that which are super easy to calculate on input to the database, but less easy/efficient to calculate whilst querying the database.

Reply to this Comment

I was just given a project to generate 45 random minutes in a quarter to randomly pair with a user. This gave me some excellent ideas.

Thanks.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
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.