Avatar of Lee R Liddick Jr
Lee R Liddick Jr
Flag for United States of America asked on

Calculating date/time variables between two dates

I did a search and found some examples but none that are working and none that are giving me what I want.  Just a basic DateDiff really isn't working for me either.

I have a StartDate and an EndDate in a query.  The hard data from the query could look like this:
StartDate                                       EndDate
11/11/2010 5:00:00 AM           11/12/2010 12:01:05 PM    

I need to display the difference between these two fields as:
1 day, 7 hours, 1 minute, and 5 seconds


     
Web ServersJScriptColdFusion Language

Avatar of undefined
Last Comment
_agx_

8/22/2022 - Mon
SOLUTION
jasonduan

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
_agx_

Adapted from http://www.cflib.org/index.cfm?event=page.udfbyid&udfid=377


<!--- Simulate query values --->
<cfset qry.StartDate = createDateTime(2010, 11, 11, 5, 0, 0)>
<cfset qry.EndDate   = createDateTime(2010, 11, 12, 12, 1, 5)>

<cfset duration = fullDuration(qry.startDate, qry.EndDate)>
<cfdump var="#duration#">

<cffunction name="fullDuration" returntype="struct">
	<cfargument name="startDate" type="date">
	<cfargument name="endDate" type="date">
	<cfset var duration = structNew()>
	<cfif dateCompare(arguments.startDate, arguments.endDate) gt 0>
		<cfthrow message="StartDate cannot be greater than EndDate">
	</cfif>
	<cfset duration.years = dateDiff("yyyy", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("yyyy", -duration.years, arguments.endDate)>
	<cfset duration.days = dateDiff("d", arguments.StartDate, arguments.endDate)>
	<cfset duration.months = dateDiff("m", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("m", -duration.months, arguments.endDate)>
	<cfset duration.days = dateDiff("d", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("d", -duration.days, arguments.endDate)>
	<cfset duration.hours = dateDiff("h", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("h", -duration.hours, arguments.endDate)>
	<cfset duration.minutes = dateDiff("n", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("n", -duration.minutes, arguments.endDate)>
	<cfset duration.seconds = dateDiff("s", arguments.StartDate, arguments.endDate)>
	<cfreturn duration >
</cffunction>

Open in new window

_agx_

jasonduan - I like the MOD (%) approach :)
_agx_

@leerljr68

Though both should work, I'd go with jasonduan's approach ;-)
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Lee R Liddick Jr

ASKER
Wasn't sure where to put jasonduans approach...i was working on your stuff because I understood that a little better.  Hahahaha
_agx_

Just put it in your query, substituting the column name for the variables.  Personally I'd make it separate columns (ie TotalDays, TotalHours, etc... ) instead of one big string  But it's up to you

SELECT  StartDateColumn, EndDateColumn,
             STR(DATEDIFF(day, StartDateColumn, EndDateColumn))  AS TotalDays  ,
             STR(DATEDIFF(hour, StartDateColumn, EndDateColumn % 24) + AS TotalHours ,
             ....
FROM    YourTable

You could also put it in a udf. All depends on how you want to slice it.
Lee R Liddick Jr

ASKER
This is what I have as my query:

        <cfquery dbtype="query" name="getDuration">
        SELECT             dtEventStart, dtEventEnd,
                        STR(DATEDIFF(day, dtEventStart, dtEventEnd)) AS TotalDays,
                        STR(DATEDIFF(hour, dtEventStart, dtEventEnd % 24)) AS TotalHours,                
                        STR(DATEDIFF(minute, dtEventStart, dtEventEnd % 60)) AS TotalMinutes,                
                        STR(DATEDIFF(second, dtEventStart, dtEventEnd % 60)) AS TotalSeconds                
        FROM        qrySelEvent                    
        </cfquery>

But I am getting a CF error:
Query Of Queries syntax error.
Encountered "(. Incorrect Select Statement, Expecting a 'FROM', but encountered '(' instead, A select statement should have a 'FROM' construct.

But I have a FROM statement?  I don't get it?
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
_agx_

You can't do it in a QoQ.  Those are sql server only functions. So you either have to do it in your original database query, or not at all.
Lee R Liddick Jr

ASKER
Ahhhh, well took it out of the QoQ:
        <cfquery datasource="myds" name="getDuration">
        SELECT             dtEventStart, dtEventEnd,
                        STR(DATEDIFF('d', dtEventStart, dtEventEnd)) AS TotalDays,
                        STR(DATEDIFF('h', dtEventStart, dtEventEnd % 24)) AS TotalHours,                
                        STR(DATEDIFF('n', dtEventStart, dtEventEnd % 60)) AS TotalMinutes,                
                        STR(DATEDIFF('s', dtEventStart, dtEventEnd % 60)) AS TotalSeconds                
        FROM        tbl_event
        WHERE     intEventId = '#qrySelEvent.intEventID#'
        </cfquery>

But now I get this CF error:
Error Executing Database Query.  
[Macromedia][SQLServer JDBC Driver][SQLServer]Invalid parameter 1 specified for datediff.  
Lee R Liddick Jr

ASKER
and if I leave it like it was originally shown:
                        STR(DATEDIFF(day, dtEventStart, dtEventEnd)) AS TotalDays,
                        STR(DATEDIFF(hour, dtEventStart, dtEventEnd % 24)) AS TotalHours,                
                        STR(DATEDIFF(minute, dtEventStart, dtEventEnd % 60)) AS TotalMinutes,                
                        STR(DATEDIFF(second, dtEventStart, dtEventEnd % 60)) AS TotalSeconds    
I get this:
Error Executing Database Query.  
[Macromedia][SQLServer JDBC Driver][SQLServer]Invalid operator for data type. Operator equals modulo, type equals datetime.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
_agx_

>> (DATEDIFF('d', dtEventStart, dtEventEnd)

Sql server doesn't use quotes around the intervals (day, hour, ...).  Go back to what you had before

STR(DATEDIFF(day, dtEventStart, dtEventEnd)) AS TotalDays,
....
ASKER CERTIFIED SOLUTION
_agx_

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Lee R Liddick Jr

ASKER
The parenthesis was it...it all works now!  Thank you all.
Lee R Liddick Jr

ASKER
The accepted solution is not working...we are finding this:

Start = 11/26/2010 10:08:00 AM
End = 11/26/2010 4:00:00 PM
The end result is coming up:  6 hours 52 minutes
The correct result should be 5 hours 52 minutes

Another Example:
Start = 11/23/2010 6:57:00 AM
End = 11/23/2010 7:18:00 PM
The end result is coming up:  1 hour 21minutes
The correct result should be just 21 minutes


<cfquery datasource="mydsn" name="getDuration">
   SELECT   dtEventStart, dtEventEnd,
               DATEDIFF(d, dtEventStart, dtEventEnd) AS TotalDays,
               DATEDIFF(hh, dtEventStart, dtEventEnd) % 24 AS TotalHours,
               DATEDIFF(n, dtEventStart, dtEventEnd) % 60 AS TotalMinutes
   FROM    myTable                    
   WHERE   ID = '#ID#'
</cfquery>
Outage Duration:
<cfoutput query="getDuration">
#TotalDays# day(s), #TotalHours# hour(s), #TotalMinutes# minute(s)
</cfoutput>

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
_agx_

At a guess, could it be a DST issue? Let me run a few tests and see what results I get.
Lee R Liddick Jr

ASKER
I figured I would play around with your suggestion and I got that to work...
<!--- get query values --->
<cfquery datasource="myDNS" name="getDuration">
        SELECT 		dtEventStart, dtEventEnd             
        FROM        myTable                    
        WHERE     	intID = '#ID#'
</cfquery>

<cfoutput>
<cfset qry.StartDate = #getDuration.dtEventStart#>
<cfset qry.EndDate   = #getDuration.dtEventEnd#>
</cfoutput>
<cfset duration = fullDuration(qry.startDate, qry.EndDate)>

<cffunction name="fullDuration" returntype="struct">
	<cfargument name="startDate" type="date">
	<cfargument name="endDate" type="date">
	<cfset var duration = structNew()>
	<cfif dateCompare(arguments.startDate, arguments.endDate) gt 0>
		<cfthrow message="StartDate cannot be greater than EndDate">
	</cfif>
	<cfset duration.years = dateDiff("yyyy", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("yyyy", -duration.years, arguments.endDate)>
	<cfset duration.months = dateDiff("m", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("m", -duration.months, arguments.endDate)>
	<cfset duration.days = dateDiff("d", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("d", -duration.days, arguments.endDate)>
	<cfset duration.hours = dateDiff("h", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("h", -duration.hours, arguments.endDate)>
	<cfset duration.minutes = dateDiff("n", arguments.StartDate, arguments.endDate)>
	<cfset arguments.endDate = dateAdd("n", -duration.minutes, arguments.endDate)>
	<cfset duration.seconds = dateDiff("s", arguments.StartDate, arguments.endDate)>
	<cfreturn duration >
</cffunction>
 


Outage Duration:
<cfoutput>
<cfif #duration.days# gt 0>
 	#duration.days# day(s), 
</cfif>
<cfif #duration.hours# gt 0>
 	#duration.hours# hour(s), 
</cfif>
<cfif #duration.minutes# gt 0>
 	#duration.minutes# minute(s) 
</cfif>
</cfoutput>

Open in new window

_agx_

Nah, that wasn't it.  I should have checked the proposed query more closely.  Seems MS SQL calculates the date boundaries differently than CF (ie *not* partial units). I think you'll need to use the minutes instead to get partial hours.  Either that or use the CF version

Not highly tested yet. But something like this should calculate the right hours:

ie 0 days 5 hours, 51 minutes.

SELECT   dtEventStart, dtEventEnd,
               DATEDIFF(d, dtEventStart, dtEventEnd) AS TotalDays,
               DATEDIFF(n, dtEventStart, dtEventEnd) % (24*60) /60 AS TotalHours,
               DATEDIFF(n, dtEventStart, dtEventEnd) % 60 AS TotalMinutes
FROM      myTable                    
WHERE   ID = '#ID#'

Your help has saved me hundreds of hours of internet surfing.
fblack61
_agx_

Sorry, I didn't see your comment before posting. My remark "Nah, that wasn't it." was referring to my guess it might be a DST issue.  It wasn't ;-)
Lee R Liddick Jr

ASKER
Yeah I figured that...no biggie, I got your original cf version to work.  Thanks for the quick response, as always, aqx!
_agx_

Anytime!
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.