dateDiff returning wrong value - coldfusion

I have a variable called date1 which contains a ColdFusion date/time object generated using parseDateTime. When I dump the variable I get {ts '2014-12-20 15:46:57'}.
I have another variable called date2 which contains another ColdFusion date/time object generated by dateConvert("local2utc",now()). When I dump the variable I get {ts '2014-12-20 15:49:40'}.
But when I do dateDiff("s",date1,date2) I get -21436 which is far too many seconds. Can anybody explain why this happening? I think it might be a time zone issue but I can't get my head around it.
Repro code
<cfset dtString = "Saturday, December 20, 2014 05:07:30 PM">
<cfset dtObject = parseDateTime(dtString)>
<cfdump var="#dtObject#">
<cfset utcNow = dateConvert("local2utc",now())>
<br><br><cfdump var="#utcNow#">
<br><br><cfdump var="#dateDiff("s",dtObject,utcNow)#">

The cause of this issue seems to be due to the bug described at https://bugbase.adobe.com/index.cfm?event=bug&id=3338974.
As described at the above URL 'the variable returned from DateConvert("local2Utc",now()) seems to carry around the offset from local to UTC. When, you use that variable for just about anything (including cfqueryparam), the value you get back is off by the amount of the offset (i.e. back to the value you passed in)'.
A workaround seems to be to convert the date to a string after conversion. I have created a simple wrapper function for this as follows:
<cffunction name="local2utc" output="no">
<cfargument name="date">
<cfreturn dateConvert("local2utc",arguments.date).toString()>
</cffunction>

Another fix for this is to use parseDateTime.
<cfset localDate = now()>
<cfset utcDate = DateConvert("local2utc", localDate)>
<cfset utcfix = parseDateTime(utcDate)>
utc epoch: #DateDiff("s", "January 1 1970 00:00", utcfix)#<br>
loc epoch: #DateDiff("s", "January 1 1970 00:00", localDate)#

Related

Nullif - using in Coldfusion

Looking for a little help with this code. Without posting the entire file which is way to big I just need a little help with using Nullif in Coldfusion.
I could I guess use it in my SQL statment, but for the sake of learning I am wondering if it can be used when setting variables as follows :-
The code doesn't throw any errors but I'd like to know where I would place the 0 after the Nullif.
<cfif AE_C NEQ 0>
<cfset AE_P=AE_T/AE_C>
<cfset AE_A=AE/AE_C*100>
<cfset AE_B = AE-AE_C/H8*H9>
<cfset AE_D=AE/H9*H8>
<cfelse>
<cfset AE_P=ISNULL(AE_T/NULLIF(AE_C))>
<cfset AE_A=ISNULL(AE/NULLIF(AE_C*100))>
<cfset AE_B=ISNULL(AE-AE_C/NULLIF(H8*H9))>
<cfset AE_D=ISNULL(AE/NULLIF(H9*H8))>
</cfif>
Hoping it can be done this way.
IMPORTANT: Your code is not showing any error because ISNULL is masking the error.
Also NULLIF is not a valid ColdFusion function. I believe the reason why there is no error in your page because, ColdFusion ISNULL() function seems to be a very versatile one and showing some undocumented characteristics. ISNULL() does not return an error even if the expression inside it is defined or not if the expression is syntactically valid.
eg.
ISNULL(AE_T/NULLIF(AE_C)) // No error because AE_T/NULLIF(AE_C) is a valid statement.
What you could do as an alternative is the following.
The following is a bit hacky, but you can check out the function val(). It will return 0 for any string that is not a number (check the doc for more details).
NULLIF(AE_C) becomes val(AE_C).
<cfset AE_P=ISNULL(AE_T/val(AE_C))>
Still if the val() return 0, then the output of ISNULL() will be YES, because division by 0 throws error.
This is some code that was written by Ben Nadel that I've found to resolve the error, perhaps someone can assist me in how I would implement it as I just can't get my head around it.
<!---
Do SQL division with divide-by-zero protection. But this,
time, let's provide a default value if the division is
not valid.
--->
<cfquery name="qDivision" datasource="#REQUEST.DSN.Source#">
SELECT
(
ISNULL(
(45 / NULLIF( 0, 0 )),
0
)
) AS value
;
</cfquery>
<!--- Output resulting value. --->
[ #qDivision.value# ]
This is more a comment than an answer. See RRK's answer about NULLIF not being a valid ColdFusion function and ISNULL() hiding an error.
My comment is more about the logic of your operation. You don't need to do some of the steps in your <CFELSE>
Original:
<cfif AE_C NEQ 0>
<cfset AE_P=AE_T/AE_C>
<cfset AE_A=AE/AE_C*100>
<cfset AE_B = AE-AE_C/H8*H9>
<cfset AE_D=AE/H9*H8>
<cfelse>
<cfset AE_P=ISNULL(AE_T/NULLIF(AE_C))>
<cfset AE_A=ISNULL(AE/NULLIF(AE_C*100))>
<cfset AE_B=ISNULL(AE-AE_C/NULLIF(H8*H9))>
<cfset AE_D=ISNULL(AE/NULLIF(H9*H8))>
</cfif>
I'm assuming you're using the NULLIF() to prevent divide by zero error.
First, in the languages I'm familiar with, NULLIF() requires two arguments: NULLIF(a,b) so that if a is not equal to b, it will return a, otherwise it will return NULL.
That said, your cfif says that if AE_C is not 0 then do x, else do y. I'm assuming it should be <cfset AE_P=ISNULL(AE_T/NULLIF(AE_C,0))>. If you extrapolate that out, you'd get AE_T/NULLIF(0,0) == AE_T/NULL == NULL. So you can just short-circuit that block and just set AE_P=NULL. But you also have the ISNULL() function around that, so that will always be true also. And ISNULL() (except in ColdFusion) also takes 2 arguments. In CF, it returns TRUE/FALSE (or YES/NO to be pedantic). So now you've essentially done <cfset AE_P = YES/TRUE>. I'm guessing that wasn't your original intent. So ISNULL() probably isn't appropriate here. In SQL, ISNULL(a,b) would mean that if a is NULL, return b. So (in SQL) you could essentially do AE_P = ISNULL(x,0) and that would mean that if AE_C was 0, rather than getting the divide by zero error, you could just set AE_P = 0.
TLDR; There isn't a NULLIF() function in ColdFusion, so if you're trying to prevent the div0 errors, you'll have to either do it in your SQL or modify your ColdFusion sets:
<cfif AE_C NEQ 0>
<cfset AE_P=AE_T/AE_C>
<cfset AE_A=AE/AE_C*100>
<cfelse>
<cfset AE_P=0>
<cfset AE_A=0>
</cfif>
I don't know the flow of your code, so I don't know how H8 and H9 are affected by AE_C, so you may have to check those for 0 also.
But, I'd still go back to my usual belief that if these calculations are used in SQL and not really in code, then they should be done in SQL rather than being passed out to the app server and then back to the SQL. Again, though, I don't know what your code is doing, so it may be more appropriate to have those calcs in code.

CFSET Invoking Function without variable

New pretty new with this language, started code with it this week.
So my problem is the new company that I started with uses CF11 and they mainly only code with tags. I want to know if is possible to call cfset without a variable declaration.
If not what is the better way to call functions (that don't have return) with tags?
<cfset myFunction()>
I usually call my initiate functions at cfset, but they all have returning.
<cfset something = #initSomething()#>
Yes, invoking a function without capturing the result is perfectly fine. Sadly, there used to be a lot of that syntax in older CF documentation. It gave the erroneous impression you MUST capture the result of a function (and use extra pound signs everywhere). Neither is true. Even if a function does return something, you're not required to capture the result. Only if you wish to use it for something later. You're always free to invoke a function and completely ignore the result. So both of these are valid:
<!--- 1. capture result --->
<cfset result = getTimeNow()>
<!--- 2. ignore result --->
<cfset getTimeNow()>
<!--- sample function --->
<cffunction name="getTimeNow" return="date">
<cfreturn now()>
</cffunction>
Technically, there's nothing stopping you from capturing the result of a function that doesn't return anything. However, the "result" variable will be undefined, so it really serves no purpose.
<cfset result = doNothing()>
<!--- this will error --->
<cfoutput>#result#</cfoutput>
<!--- sample function --->
<cffunction name="doNothing" return="void">
<!--- function that returns nothing --->
</cffunction>

Now() Value in Coldfusion

I am trying to set the expression #Now() + CreateTimeSpan('30','0','0','0')# in a cookie and manipulating the values in a JS function.
The value of the expression is being displayed as 41720.406? What does this value mean?
Any pointers would be really helpful.
41720.406? What does this value mean?
To answer your question, apparently it represents a number of days from the CF epoch ie 1899-12-30, plus or minus time zone offsets.
<cfscript>
cfEpoch = createDate(1899, 12, 30);
// add number of whole days ie 41720
finalDate = dateAdd("d", 41720, cfEpoch );
// add partial days ie partialDay * millisecondsPerDay
finalDate = dateAdd("l", 0.406 * 86400000, finalDate);
// Result: Today's date and time plus 30 days
writeOutput( "finalDate="& dateConvert("local2UTC", finalDate) );
</cfscript>
Having said that, it is much simpler to use date functions as others suggested, rather than mucking with time span objects.
You may want to use DateAdd() instead. So use DateAdd('d', 30, Now()).
<cfset x = DateAdd('d', 30, now())>
<cfoutput>#toScript(x, "time")#</cfoutput>
output:
time = new Date(2014, 2, 22, 2, 36, 26);
Since you mentioned cookies, it's worth pointing out that dates for cookies use a specific format, i.e. Thu, 01-Jan-1970 00:00:01 GMT
This is not how CF formats dates by default - when you output #SomeDate# the format used is {ts '1970-01-01 00:00:01'} instead.
Here's a function that returns a date as a string in the format cookies use:
<cffunction name="formatCookieDate" returntype="String" output=false access="public">
<cfargument name="DateTime" type="Date" default=#Now()# />
<cfargument name="isUtc" type="String" default=false />
<cfif NOT Arguments.isUtc >
<cfset Arguments.DateTime = DateConvert('local2utc',Arguments.DateTime) />
</cfif>
<cfreturn DateTimeFormat( Arguments.DateTime ,'E, dd Mmm yyyy HH:nn:ss' ) & ' GMT' />
</cffunction>
You can use it like this:
formatCookieDate( Now() + 30 )
Whilst some prefer using DateAdd, it is perfectly valid to add days directly - though you might want to consider if you're actually wanting to add 30 days versus adding 1 month.
NOTE: On versions prior to CF10 you'll need to split the DateTimeFormat into DateFormat and TimeFormat and update the masks accordingly.

How to format Stripe timestamp in Coldfusion

One of the fields I get back from a Stripe request is the created field, which contains the value "1351894331". I have tried using DateFormat() in Coldfusion to format this, but that did not work out. I imagine this is some sort of date type / timestamp that needs to be converted before DateFormatting it, but what do I need to use? What type of date format is that?
Thanks
That could be a number of seconds from 1970-01-01? This code:
<cfoutput>#dateAdd("s", 1351894331, createDateTime(1970, 1, 1, 0, 0, 0))#</cfoutput>
Outputs:
{ts '2012-11-02 21:12:11'}
Would that be around about the timestamp you'd expect?
Have you read the "Stripe" docs? If I wanted to know how something worked, my first port of call would be to RTFM. To put it appropriately, if slightly indelicately.
On a whim, I googled "what format is stripe created timestamps in" for you. The first link goes to here. The second link goes to the relevant question on strip.com's docs, which say:
Yes, all Stripe times are in UTC represented as the Unix epoch.
And just to verify the Unix Epoch date, I googled that too. And the answer is:
Unix time, [...] is [...] defined as the number of seconds that have elapsed since midnight Coordinated Universal Time (UTC), 1 January 1970
Of course if you're meaning some other sort of "stripe", you're gonna have to elaborate.
That's a unix timestamp - number of seconds since 1 Jan 1970 - which is used often as a method for storing dates.
But not in CFML, where dates are handled as a floating number of days since 30-Dec-1899.
To convert from a unix timestamp to a CF date number, you need to divide by number of seconds in a day (86400), then add the number of days between the two dates.
<cfset UnixTime = 1351894331 />
<!--- days between 1-Jan-1970 and 30-Dec-1899) --->
<cfset UnixTimeOffset = 25569 />
<cfset CfTime = UnixTimeOffset + UnixTime/86400 />
You can then use the CfTime variable in any date functions and they will work as usual.
Stripe is a supported gateway in CFPAYMENT (a well-tested library that helps you avoid writing e-commerce plumbing code) and has helper functions for the date conversions. You can see the methods here:
https://github.com/ghidinelli/cfpayment/blob/master/api/gateway/stripe/stripe.cfc
<cffunction name="dateToUTC" output="false" access="public" returntype="any" hint="Take a date and return the number of seconds since the Unix Epoch">
<cfargument name="date" type="any" required="true" />
<cfreturn dateDiff("s", dateConvert("utc2Local", "January 1 1970 00:00"), arguments.date) />
</cffunction>
<cffunction name="UTCToDate" output="false" access="public" returntype="date" hint="Take a UTC timestamp and convert it to a ColdFusion date object">
<cfargument name="utcdate" required="true" />
<cfreturn dateAdd("s", arguments.utcDate, dateConvert("utc2Local", "January 1 1970 00:00")) />
</cffunction>

Transpose query in ColdFusion

I have a simple cfquery which outputs 3 columns with their respective data. The columns are name, address and age.
I want to transpose this set of data so that the names become the columns and the address and age are displayed under each column.
I know that we can use QueryAddColumn or something like this for this issue. Can someone help me out with this problem?
EDIT:
Based on the comment below this is the intended output:
Oct 2011 Nov 2011 Dec 2011 Jan 2012 Feb 2012
NumberofPeople NumberofPeople NumberofPeople NumberofPeople NumberofPeople
EmploymentRate EmploymentRate EmploymentRate EmploymentRate EmploymentRate
I have included a sample data row at the top where you would put your cfquery statement.
<cfset firstQuery = queryNew("date,NumberofPeople,EmploymentRate")>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","OCT_2011",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","28",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","50%",aRow)>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","NOV_2011",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","28",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","56%",aRow)>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","DEC_2011",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","29",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","55%",aRow)>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","JAN_2012",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","30",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","52%",aRow)>
<!--- Will Create new query with names as column headers--->
<cfset newQuery = queryNew(valueList(firstQuery.date,','))>
<!--- Will Create new query with names as column headers--->
<cfset people = queryAddRow(newQuery)>
<cfset rate = queryAddRow(newQuery)>
<cfloop query='firstQuery'>
<!---Syntax for this function is: QuerySetCell(query, column_name, value [, row_number ]) --->
<cfset querySetCell(newQuery,firstQuery.date,firstQuery.NumberofPeople,people)>
<cfset querySetCell(newQuery,firstQuery.date,firstQuery.EmploymentRate,rate)>
</cfloop>
<cfdump var="#newQuery#">
<cfdump var="#ArrayToList(newQuery.getColumnNames())#">
This is How I would Do it, But I can't think of why I would do it. I'd be interested to hear your use case. Anyway, I hope this helps.
(P.S This is tested in CF9, so you should be able to copy and paste it to test for yourself.)
EDIT -(Again):
Forgot to mention, this can only work if the names your retrieveing from the DB are valid column names, so no spaces (In this example spaces in dates have been replaced by underscores)!
>>> New code snippet for the updated data structure, the function valueList(firstQuery.date,',') doesn't re-order your columns. The columns are re-ordered on output when dumping. I have used the function ArrayToList(newQuery.getColumnNames()) to show that internally CF maintains the column order and you need only ask it nicely. You should be able to use all this information to nicely output your data how you need it.
Maybe I'm missing something but it seems like a simple SQL query with the ORDER BY clause would work. Something like this:
<cfquery name="myquery" datasource="yourdatasourcename">
select name, address, age
from tablename
order by name
</cfquery>
Then in your ColdFusion output page, you can use the tag with the group attribute. Something like this:
<cfoutput query="myquery">
<p>name = #name#
<cfoutput group="name">
age = #age#
address = #address#<br />
</cfoutput>
</p>
</cfoutput>
Obviously, you can format the output however you wish.
EDIT --
If you are wanting to display like:
Mary Joe Sam Suzie
28 36 25 42
123 Maple 16 Oak 3723 Street 832 Busy St.
Perhaps something like (I have not tested this, just brainstorming):
<cfoutput query="myquery" group="name">
<div style="float:left;">name = #name#
<cfoutput>
<p>
age = #age#<br />
address = #address#
</p>
</cfoutput>
</div>
</cfoutput>
I think you are describing a pivot query in SQL.