Ask Ben: Appending Times To Date/Time Objects

Posted July 19, 2006 at 9:32 AM

Tags: ColdFusion, Ask Ben

In ColdFusion, how can I append a time to a date?

This question is a bit ambiguous so I will try to answer both questions it might be. I think you are asking one of the two following questions:

  1. How can I add or replace the time portion of a date/time object so that the resultant date/time object has the original date and the given time?
  2. How can I add a given amount of time to a given date/time object?

If you have been following my earlier posts, you will see that you can handle date/time objects in ColdFusion in many, many ways. This means that the problems above can be solved in many ways. To start with, I will discuss the possible solutions. Then, I will go over time testing so you can see which one is actually faster.

For starters, I am going to tackle the idea of replacing the time part of a date/time object with the given time parameters. This will not change the date portion, only the time portion. For this section, I am going to assume that we have the following date/time object:

 Launch code in new window » Download code as text file »

  • <cfset dtNow = "2006-07-19 08:43:15 AM" />

This will give us a date/time object that has both a date and a time portion.

Solution A1: We can use the built-in ColdFusion method CreateDateTime(). This method allows us to create a date/time object by supplying all of the individual parts (year, month, day, hours, minutes, seconds). Since we only want to "create" the time part, you can pass in the year, month, and day from the existing date/time object:<br>

 Launch code in new window » Download code as text file »

  • <!--- Create a new date with a time portion. --->
  • <cfset dtOne = CreateDateTime(
  • Year( dtNow ),
  • Month( dtNow ),
  • Day( dtNow ),
  • 18, <!--- 6 PM. --->
  • 00, <!--- 0 Minutes. --->
  • 00  <!--- 0 Seconds. --->
  • ) />
  •  
  • <!--- Dump out result. --->
  • <cfdump var="#CreateODBCDateTime( dtOne )#" /><br>

Here, you can see that we are only setting the time parts but keeping the old date parts. Also, I am using the ColdFusion method CreateODBCDateTime() here (and throughout the entry) because it will give us a consistent formatting of both the date and time parts of the date/time object with minimal coding. This is for display purposes only. I would not use this to format dates in my code.

Solution A2: We can treat the date/time object as a number whose integers are the days and whose decimals are the time part (day fractions). To do so, we can round out the date, creating a number that has no time, then add a time span to it:<br />

 Launch code in new window » Download code as text file »

  • <!--- Create a new date based on the rounded date and a time span. --->
  • <cfset dtTwo = (
  • Round( dtNow ) +
  • CreateTimeSpan(
  • 0,  <!--- Days. --->
  • 18, <!--- Hours. --->
  • 0,  <!--- Minutes. --->
  • 0   <!--- Seconds. --->
  • )
  • ) />
  •  
  • <!--- Dump out result. --->
  • <cfdump var="#CreateODBCDateTime( dtTwo )#" /><br>

This method has the advantage that you don't have to pass in the three parts of the original date object but instead just pass in the date object as a whole to the Round() method. While you cannot see it if you use my CFDump tag, keep in mind that when you Round() the date and use CreateTimeSpan(), ColdFusion is converting the date/time object to a floating point number. This is STILL a date, but you need to format it for display (can be used internally as a date without formatting).

Solutions A3: You can treat the date/time object as a formatting string and then just text-append the time part to the date part:<br />

 Launch code in new window » Download code as text file »

  • <!--- Create a date/time as a string object. --->
  • <cfset dtThree = (
  • DateFormat( dtNow, "yyyy-mm-dd" ) &
  • " " &
  • "18:00:00"
  • ) />
  •  
  • <!--- Dump out result. --->
  • <cfdump var="#CreateODBCDateTime( dtThree )#" /><br>

This method will create the string "2006-07-19 18:00:00" which ColdFusion will properly treat as a date/time object. Even before testing though, I can tell you that this is slow. DateFormat() is a slow function and string concatenation is slow.

That's all I can really think of for problem one. Now, let's talk about problem two, adding time to an existing date/time object so that both the date and the time parts are potentially updated. There's really only one way I can think about doing this that isn't entirely crappy and that is to simply add the time span to the date/time object:

 Launch code in new window » Download code as text file »

  • <!--- Create a new date by adding a time span. --->
  • <cfset dtFour = (
  • dtNow +
  • CreateTimeSpan(
  • 0, <!--- Days. --->
  • 2, <!--- Hours. --->
  • 0, <!--- Minutes. --->
  • 0  <!--- Seconds. --->
  • )
  • ) />
  •  
  • <!--- Dump out result. --->
  • <cfdump var="#CreateODBCDateTime( dtFour )#" /><br>

The equation above forces the date/time object (dtNow) to be converted to a floating point number so that it can play well with CreateTimeSpan(). Then, we add the time span (another floating point number) and get the resultant date as a floating point number (which we already discussed).

Keep in mind that while our examples have used the CreateTimeSpan() method to create time spans less than a day, if you had over 24 hours or set the day argument, the date portion of the resultant date/time object will also be altered.

One final note, you CANNOT use DateAdd() and CreateTimeSpan() to add fractions of a day. This would be nice, but DateAdd() requires the use of integer values and CreateTimeSpan() created floating point numbers.

Ok, so those are the potential solutions, now let's test which ones of the first set are the fastest.

 Launch code in new window » Download code as text file »

  • <cftimer label="One" type="outline">
  • <cfloop index="intI" from="1" to="1000">
  •  
  • <cfset dtOne = CreateDateTime(
  • Year( dtNow ),
  • Month( dtNow ),
  • Day( dtNow ),
  • 18, <!--- 6 PM. --->
  • 00, <!--- 0 Minutes. --->
  • 00  <!--- 0 Seconds. --->
  • ) />
  •  
  • <cfset WriteOutput(
  • CreateODBCDateTime( dtOne )
  • ) />
  •  
  • </cfloop>
  • </cftimer>

... This runs on average at about 540 ms.

 Launch code in new window » Download code as text file »

  • <cftimer label="Two" type="outline">
  • <cfloop index="intI" from="1" to="1000">
  •  
  • <cfset dtTwo = (
  • Round( dtNow ) +
  • CreateTimeSpan(
  • 0, <!--- Days. --->
  • 18, <!--- Hours. --->
  • 0, <!--- Minutes. --->
  • 0 <!--- Seconds. --->
  • )
  • ) />
  •  
  • <cfset WriteOutput(
  • CreateODBCDateTime( dtTwo )
  • ) />
  •  
  • </cfloop>
  • </cftimer>

... This runs on average at about 250 ms. This is less than have the time of the CreateDateTime() method. Who knows what is going on underneath the ColdFusion hood, but you can see that the CreateDateTime() method uses 4 function calls where as the second solution is only two method calls. Hmmmm.

 Launch code in new window » Download code as text file »

  • <cftimer label="Three" type="outline">
  • <cfloop index="intI" from="1" to="1000">
  •  
  • <cfset dtThree = (
  • DateFormat( dtNow, "yyyy-mm-dd" ) &
  • " " &
  • "18:00:00"
  • ) />
  •  
  • <cfset WriteOutput(
  • CreateODBCDateTime( dtThree )
  • ) />
  •  
  • </cfloop>
  • </cftimer>

... This runs on average at about 460 ms. First off, I am SHOCKED that the string-concatenation method runs faster than the CreateDateTime() method. SHOCKED! Especially as this one uses DateFormat() which is very slow.

Well, shock or no shock, it is clear that treating the date/time object as a number and then doing math on it is going to be the fastest solution. Math always is :) But, more than fast, you have to decide for yourself which is going to make your code most readable and therefore the most maintainable. Happy coding!

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

There are no comments posted for this web log entry.


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 7, 2009 at 5:53 PM
Ask Ben: Javascript String Replace Method
You can find here an advanced function that prepared with javascript replace function. This can make the first letters of words, sentences, lines and whatever you define automatically: http://www.m ... read »
Andrew Neely
Nov 7, 2009 at 4:56 PM
A Moment That Touched Me - The Fountainhead
Ben, Glad you enjoyed the podcast. Yeah, the Tank Riot guys can get really chatty during the episodes, but that's part of the charm of it for me. They've covered everything from Nichola Tesla to Cha ... read »
Nov 7, 2009 at 4:43 PM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
Is it possible to make some more MenĂ¼`s ? ... read »
Jill
Nov 7, 2009 at 11:40 AM
How To Unformat Your Code (Like A Pro)
Derek, I think you might be right - sweet! Thanks for the link :) ... read »
Nov 7, 2009 at 11:25 AM
How To Unformat Your Code (Like A Pro)
I think it would be way easier to just use this http://www.logichammer.com/html-formatter/ He just released v3 and it rocks. ... read »
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »