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.
Related
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)#
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>
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.
I've just encountered CF's unwanted "feature" which involves stripping leading zeroes from the values returned to an autosuggest input. I was thinking I could prepend some character to the values and strip them out after the return, but have hit a snag. I'm modifying an existing function, which looks like this:
<cffunction name="lookupTailNumber" access="remote" returntype="Array" >
<cfargument name="search" type="any" required="false" default="">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(1)>
<!--- Do search --->
<cfquery name="data">
SELECT DISTINCT SERIAL_NUMBER AS list
FROM aircraft_status
WHERE SERIAL_NUMBER LIKE '%#trim(ARGUMENTS.search)#%'
ORDER BY list
</cfquery>
<!--- Build result array --->
<cfloop query="data">
<cfset ArrayAppend(result, list)>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
which returns a response which looks like this:
[3001.0,1.00002E8,1.00002001E8,1.00002002E8,1.00002003E8,1.00002004E8]
or in JSON format:
0
3001
1
100002000
2
100002001
3
100002002
4
100002003
where all the results have had leading zeroes stripped away. I've tried modifying the query to prepend a character to each value:
<cfquery name="data">
SELECT DISTINCT (concat(' ', SERIAL_NUMBER)) AS list
FROM aircraft_status
WHERE SERIAL_NUMBER LIKE '%#trim(ARGUMENTS.search)#%'
ORDER BY list
</cfquery>
which returns this:
[" 0000003001"," 0100002000"," 0100002001"," 0100002002"," 0100002003"," 0100002004"]
so you'd think all was well, right? Problem: when returned, none of the values show up in the autosuggest field!!! I've also tried prepending different characters, including numbers, with no luck. Looking at the elements in yui-ac-bd div > ul, none are populated or displayed.
The input is declared like so:
<cfinput style = "width:300px;"
class = ""
type="text"
name="txtvalueFilter"
maxlength="15"
id="txtvalueFilter"
autosuggest="cfc:mycfcpath({cfautosuggestvalue})"
/>
Thoughts?
Try appending a space, so the built-in JSON serializer will treat it as a string instead of an int in JSON.
Also, make sure you have installed the latest hotfixes for your version of CF.
I wonder if u need to "Build result array". What happen if you return data.list? or, maybe use ListToArray(valueList(data.list)) instead?
I have to validate form values as integers.
I have tried something like this:
<cfloop collection="#form#">
<cfif form.value eq int(form.value)>
#form.value# is an integer
</cfif>
</cfloop>
It works as long the user does not input comma as the decimal separator, which is the default way of doing this here in Germany.
I have to use CF MX 6.1.
It would also probably help to look into the Internatational functions that are available. LSParseNumber(), for instance.
You may, if you like, desensitize the input first.
<cfset var comma = ",">
<cfset var period = ".">
<cfset form.value = replace(form.value, comma, period, "all")>
But, if all you need is to verify if a field is an integer, why don't you look at CFLib.org - IsInt ?
<cfscript>
/**
* Checks to see if a var is an integer.
* version 1.1 - mod by Raymond Camden
*
* #param varToCheck Value you want to validate as an integer.
* #return Returns a Boolean.
* #author Nathan Dintenfass (nathan#changemedia.com)
* #version 1.1, April 10, 2002
*/
function isInt(varToCheck){
return isNumeric(varToCheck) and round(varToCheck) is vartoCheck;
}
</cfscript>
Like Al Everett, I recommend using the locale specific functions:
<!--- actually *setting* the desired locale is mandatory for this to work --->
<cfset SetLocale("German (Standard)")>
<cfif CGI.REQUEST_METHOD eq "POST">
<!--- loop the FieldNames list so only real posted values are handled --->
<cfloop list="#FORM.FieldNames#" index="FieldName">
<cfif LSIsNumeric(FORM[FieldName])>
<cfset num = LSParseNumber(FORM[FieldName])>
<!--- do stuff with #num# --->
</cfif>
</cfloop>
</cfif>