ColdFusion dateformat wrong format - date

I have an input text where I get the date:
<input type="text" name="myDate" />
After submitting the form, I save this date into the database doing a dateformat:
#DateFormat(myDate, "yyyy-mm-dd")#
If the user enters: 02/19/1948, it saves correct: 1948-02-19.
But if the user enters: 02191948, it saves: 7901-05-07. Why? Does anyone know how I can fix it?
Thanks

ColdFusion's DateFormat() expects a valid date representation. ColdFusion is very sloppy when it comes to what type of input is considered valid. Safe date inputs are ODBC literals and most of ISO 8601. Beware of format pitfalls like mm/dd and dd.mm and avoid them altogether, if possible.
What you want to use is LSParseDateTime(). It allows you to specify the locale and format you expect and make ColdFusion parse a date object based on the input. It's not fail-safe though, meaning you have to try-catch it in case the input doesn't match at all. There is a fail-safe LSIsDate(), which tells you if the input is considered valid in the specified locale. But either way, it's a game of format detection. Having fixed <select> tags for month, day and year is the easiest way to avoid issues.
Loose demo for localized date input:
<cfset myLocale = "en_US">
<cfset myDateFormat = "yyyy-mm-dd">
<cfset dateByInput = "">
<cfset errorReason = "">
<cfif structKeyExists(FORM, "myDate")>
<cfif lsIsDate(FORM["myDate"], myLocale)>
<cftry>
<cfset dateByInput = lsParseDateTime(FORM["myDate"], myLocale, myDateFormat)>
<cfcatch>
<cfset errorReason = ("Your input is invalid. Please enter in the following format: " & myDateFormat)>
</cfcatch>
</cftry>
<cfelse>
<cfset errorReason = ("Your input is invalid. Please enter in the following format: " & myDateFormat)>
</cfif>
</cfif>
<cfset dateByInputIsValid = isDate(dateByInput)> <!--- note: it's sufficient to use the unlocalized date check here, since dateByInput is either not valid at all or a (universal) date object --->
<cfif dateByInputIsValid>
<!--- store date input in database --->
<cftry>
<cfset myDatasource = "exampleDS">
<cfquery datasource="#myDatasource#">
INSERT INTO `myDatabase`.`myTable` ( `myDateColumn` ) VALUES (
<cfqueryparam value="#dateByInput#" cfSqlType="CF_SQL_TIMESTAMP">
)
</cfquery>
<cfcatch>
<cfset errorReason = "Oh noes, something went wrong attempting to save your input.">
</cfcatch>
</cftry>
</cfif>
<cfoutput>
<cfif dateByInputIsValid>
<p>Date input valid: #lsDateFormat(dateByInput, myDateFormat, myLocale)#</p>
<cfif len(errorReason)>
<p>#errorReason#</p>
<cfelse>
<p>Input successfully stored in database.</p>
</cfif>
<cfelse>
<cfif len(errorReason)>
<p>#errorReason#</p>
</cfif>
<form method="post">
<input type="text" name="myDate" />
<button type="submit">send</button>
</form>
</cfif>
</cfoutput>

Related

Coldfusion: specific action after selecting an option in select

I have following code:
<cfif session.language is ("DE")>
<cfset bl=ValueList(getContent.G,",")>
<cfelseif session.language is ("FR")>
<cfset bl=ValueList(getContent.H,",")>
<cfelseif session.language is ("EN")>
<cfset bl=ValueList(getContent.I,",")>
</cfif>
<cfset tags = sizes />
<cfset bltags = bl />
<cfset tagArray = arrayNew(1) />
<cfset tagArrayDATA = arrayNew(1) />
<cfloop list="#tags#" index="tag" delimiters=",">
<cfif not ArrayFindNoCase(tagArray,tag)>
<cfset arrayAppend(tagArray, tag) />
</cfif>
</cfloop>
<cfloop list="#bltags#" index="tag" delimiters=",">
<cfif not ArrayFindNoCase(tagArrayDATA,tag)>
<cfset arrayAppend(tagArrayDATA, tag) />
</cfif>
</cfloop>
<cfoutput>
<cfif isdefined("tagArray") AND arraylen(tagArray) GT 1>
<form name="frmsize" id="frmsize" action="/index.cfm?showusage" method="post">
<cfif isdefined("tagArray") AND arraylen(tagArray) GT 1>
<div>
<select name="valuesize">
<option value="">Choose your option</option>
<cfloop from="1" to="#arraylen(tagArray)#" index="i">
<option value="#tagArray[i]#">#tagArray[i]#
<cftry>
#tagArrayDATA[i]#
<cfcatch>
</cfcatch>
</cftry>
</option>
</cfloop>
</select>
</div>
</cfif>
</form>
</cfif>
</cfoutput>
My goal is to send a value from tagArrayDATA[i] via link.
It should look like that:
<form name="frmsize" id="frmsize" action="/index.cfm?showusage&valueArrayData="#tagArrayDATA[i]#" method="post">
I don't know how to manage that because the cfloop is below the action attribute of the form.
You can't really do what you are trying to do with server side code alone as far as I can tell. But you have a couple of options. One easy one is to just Javascript to update the action when the select is changed.
The other option is to put both values in the select and parse on the end.
<cfloop from="1" to="#arraylen(tagArray)#" index="i">
<option value="#tagArray[i]#-#tagArrayDATA[i]#">
#tagArray[i]# #tagArrayDATA[i]#
</option>
</cfloop>
Then when you are parsing the data just do:
<cfset data = listToArray(FORM.valuesize,'-') />
<!-- data[1] will be the selected value of #tagArray[i]# -->
<!-- data[2] will be the selected value of #tagArrayData[i]# -->
<!-- This assumes the - will never be actually in the data, you could use a different separator -->
My guess is they are both strings and this should work, though I have no idea why you have a try/catch in the select part of your code, probably look at a better way of doing that. If you really need that, I would clean it up as.
<cfloop from="1" to="#arraylen(tagArray)#" index="i">
<cfset data = '' />
<cftry>
<cfset data = tagArrayData[i] />
<cfcatch></cfcatch>
</cftry>
<option value="#tagArray[i]#-#data#">
#tagArray[i]# #data#
</option>
</cfloop>
Though if you are processing the data on the other end, I would make sure all the data is either in the FORM or the URL scopes but not mix. I would be pissed to have to parse some form data in the FORM scope and other data in the URL scope.

Converting date to indonesian locale swaps day with month

Consider the following date entries. I want DD/MM/YYYY format for both input strings and output strings
<cfset SetLocale('indonesian') /> <!--- also set in Railo Admin --->
<cfdump var="#GetLocale()#" />
<cfdump var="#LSDateFormat('01/07/2014', 'dd/mm/yyy')#" />
<cfdump var="#LSDateFormat('31/07/2014', 'dd/mm/yyy')#" />
<cfdump var="#LSDateFormat(Now())#" />
Output:
string in <--- correct for 'indonesian'?
string 07/01/2014 <--- wrong
string 31/07/2014 <--- correct... maybe
string 31/07/2014 <--- correct... maybe
Indonesia uses DD/MM/YYYY format but Railo seems to treat the date input string as a U.S. date unless it's "invalid" (U.S. month higher than 12).
The OS locale is: LC_TIME="en_AU.UTF-8" (Australian). This locale also uses DD/MM/YYYY
So given that nothing I can see specifies a US date format and I'm using the LS variant of the function why are my date input strings being interpreted as U.S. dates?
Actually I really don't like the DD/MM changing locale based on the MM value. I'm looking for an answer that actually validates the date is DD/MM/YYYY as well (preferably using something built-in rather than a UDF).
The issue is that the date passed to lsDateFormat function is expected to be a date object. If you pass in a string coldfusion will try to convert the string into a date object for you. This automatic conversion will do this assuming the american date format.
You can test this by creating your date with the createDate function. You could quickly build your own date parsing function a sample I hacked together is found below:
NOTE: In a complete solution you will have to check if the response from the function is a unknown date and act accordingly.
<cfset SetLocale('indonesian') /> <!--- also set in Railo Admin --->
<cfdump var="#GetLocale()#" />
<cfdump var="#LSDateFormat('01/07/2014', 'dd/mm/yyy')#" />
<cfdump var="#LSDateFormat('31/07/2014', 'dd/mm/yyy')#" />
<cfdump var="#LSDateFormat(Now())#" />
<!--- Now with creating date objects--->
<cfdump var="#LSDateFormat(createDate(2014,07,01), 'dd/mm/yyy')#" />
<!--- Using our own date parser--->
<cfdump var="#LSDateFormat(udf_parseDate('01/07/2014'), 'dd/mm/yyyy')#" />
<cfdump var="#LSDateFormat(udf_parseDate('31/07/2014'), 'dd/mm/yyyy')#" />
<cffunction name="udf_parseDate" output="false" returntype="date">
<cfargument name="value" required="true" type="string">
<cfset var UNKNOWN_DATE = createDate(1900,1,1)>
<cfset var DELIMITER = "/">
<cfset var iDay = 0>
<cfset var iMonth = 0>
<cfset var iYear = 0>
<cftry>
<cfset iDay = getToken(arguments.value,1,DELIMITER)>
<cfset iMonth = getToken(arguments.value,2,DELIMITER)>
<cfset iYear = getToken(arguments.value,3,DELIMITER)>
<cfset tmp = createDate(iYear,iMonth,iDay)>
<cfcatch type="any">
<cfreturn UNKNOWN_DATE>
</cfcatch>
</cftry>
<cfreturn tmp>
</cffunction>
My advice would be to stay away from all the inbuild localisation features they more often then not don't work the way that one needs them to work in a fully localised application. especially if you need to support multiple locales at the same time. e.g. Time Zones.
UPDATE:
For the sake of completeness and technically more correct.
The locale you are setting is invalid. For a complete list of available locales do this:
<cfdump var="#Server.coldfusion.supportedlocales#">
You will then see the correct locale should be:
<cfset SetLocale('indonesian (indonesia)') />

Unable to retrieve array of dates from cfc

I was trying to implement 3 dependent drop downs in my code. But was unable to retrieve dates from my ColdFusion component. Here is the code in my .cfm template:
1st drop down
<cfselect name="city_code" class="styled-select"
bind="cfc:getcity.getcity1()"
bindonload="true" >
2nd drop down
<cfselect name="movie_id" class="styled-select"
bind="cfc:getcm.getmovies({city_code})">
</cfselect>
3rd drop down
<cfselect id="movie_id1" name="movie_id1"
class="styled-select"
bind="cfc:getcm.getdate({movie_id})"/>
In the 3rd drop down, I want to display dates for about five days from the current date. Here is my cfc code:
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<cfquery name="data2" datasource="sqldb">
select movie_id,release_date
from shows
where movie_id = '#ARGUMENTS.movie_id#'
</cfquery>
<cfset result[1][1] = "0">
<cfset result[1][2] = " Select Date">
<cfloop index="i" from="1" to="#data2.recordcount#">
<cfset result[i+1][1]=data2.movie_id[i]>
<cfset result[i+1][2]=data2.release_date[i]>
</cfloop>
<cfreturn result>
This CFC is working for me, but I have to retrieve 5 dates before release date.
k try this way murali
<cfquery name="data2" datasource="bookonline">
select tid,daysb4booking
from shows
where movie_id = '#ARGUMENTS.movie_id#'
</cfquery>
<cfset arr=ArrayNew(1)>
<cfloop index="i" from="1" to="#data2.recordcount#">
<cfset arr[i]=data2.daysb4booking[i]>
</cfloop>
<cfset num=#LSNumberFormat(arraymax(arr))#>
<cfset result[1][1] = "0">
<cfset result[1][2] = " Select Date">
<!--- convert results to array--->
<cfloop index="i" from="1" to="#num#">
<cfset result[2][1]=data2.tid[1]>
<cfset result[2][2]=dateformat(dateadd("d",i,now()))>
</cfloop>

PayPal ExpressCheckout Missing Total column

Why am I missing the total on the checkout page?
Apologies.
As my code is working, because it actually got to PayPal and does have all the field correct.
I didn't think it was necessary to post the code.
I thought it could be answered simply, "you're missing the XXXX variable in your post to PayPal."
But, seeing as this is StackOverflow, code is required.
This is COLDFUSION (yes caps because people think this is a dead/dying language).
<cffunction name="expressCheckout" access="remote" returnformat="JSON" output="false" description="Processes PayPal Subscription">
<cfargument name="L_BILLINGAGREEMENTDESCRIPTION0" type="string" required="yes" />
<cfargument name="L_BILLINGTYPE0" type="string" required="yes" />
<cfargument name="AMT" type="numeric" required="yes" />
<cfset var username = "wpp_1306278086_biz_api1.blahblah.com">
<cfset var password = "1306278555">
<cfset var signature = "someSig">
<cfset var serverURL = "https://api-3t.sandbox.paypal.com/nvp">
<cfset var version = "65.1">
<cfset requestData = StructNew()>
<cfset requestData.USER = "#USERNAME#">
<cfset requestData.PWD = "#PASSWORD#">
<cfset requestData.SIGNATURE = "#SIGNATURE#">
<cfset requestData.SUBJECT = "">
<cfset requestData.VERSION = "#version#">
<cfset requestData.METHOD = "SetExpressCheckout">
<cfset requestData.AMT = "#arguments.AMT#">
<cfset requestData.DESC = "#arguments.L_BILLINGAGREEMENTDESCRIPTION0#">
<cfset requestData.CUSTOM = "#session.rfcid#">
<cfset requestData.returnURL = "http://localhost:8500/rfc2-1/membership/payPalConfirm.cfm">
<cfset requestData.cancelURL = "http://localhost:8500/rfc2-1/membership/creditcardform.cfm">
<cfset payPalReturn = doHttppost(requestData, serverURL, "no")>
<cfset payPalReturn = getNVPResponse(#URLDecode(payPalReturn)#)>
<cfif payPalReturn.ACK EQ "Failure">
<!--- return the error message --->
<cfset payPalReturn.ERRORMESSAGE = #payPalReturn.L_LONGMESSAGE0#>
</cfif>
<cfreturn payPalReturn>
</cffunction>
This retuns a json object to the browser.
The browser then sends me to:
https://sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=SomeToken
All fine when I get to PayPal. Just missing the total in the left hand box (as diagrammed)
Try appending &useraction=commit to the PayPal redirection URL (https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-xxxxxx&useraction=commit).
Not sure of this works for billing agreements, but worth a shot. It'll work for regular payments anyway.
edit:
Actually, on second thought; since it's a billing agreement, which is not for a fixed price (otherwise you wouldn't need a billing agreement in the first place); this would be intended. Since there is no specific price to display.

Is there an easier way to manipulate checkboxes in coldfusion?

Basically, I have stored information in a database field and I want to display it again through a form.
The original form has the same checkboxes but they are always empty. The user can check the boxes off and the values are put into the database.
Graduate Courses: Fall? Spring? Summer? Stored as a list in a column named grad. (F, M, S)
They have the option to save this lovely form as a draft. When they come back to the draft I need to display what they might have already checked.
<cfif listContains(#grad#, "F") is not 0>
<input type="checkbox" name="grad" id="grad" value = "F" checked />
<cfelse>
<input type="checkbox" name="grad" id="grad" value = "F" />
</cfif>
<cfif listContains(#grad#, "S") is not 0>
<input name="grad" type="checkbox" id="grad" value = "S" checked />
<cfelse>
<input name="grad" type="checkbox" id="grad" value = "S" />
</cfif>
<cfif listContains(#grad#, "M") is not 0>
<input name="grad" type="checkbox" id="grad" value = "M" checked />
<cfelse>
<input name="grad" type="checkbox" id="grad" value = "M" />
</cfif>
Is there an easier method to doing this with cfform code?
Just curious. :)
I do it like this, as I don't really use <cfform>:
<cfloop list="F,S,M" index="g">
<input type="checkbox" name="grad" id="grad_#g#" value="#g#" #CheckedIf(ListFind(grad, g) gt 0)# />
</cfloop>
<!--- ... --->
<cfscript>
function CheckedIf(expression) {
if (arguments.expression) return 'checked="checked"';
return "";
}
</cfscript>
But the ColdFusion docs state:
[since] ColdFusion MX: Changed the cfform tag
preserveData attribute behavior: if it
is set to True, ColdFusion checks
radio and check box values only if
their value matches the posted value
for the control.
So yes, <cfform> can help you with this. Use <cfparam name="FORM.xyz" default="foobar"> to emulate the "posted value" for normal requests.