ColdFusion CFQuery Looking for Month Only - coldfusion

ColdFusion 9 using Access Database stores the Dates such as 1/12/2015, 2/22/2015, 1/21/2015 etc...
I am looking to only get Month results such as January only, Feb only etc...
I can easily pull the year only If I need it using:
<cfquery name="f" datasource="ds">
select * from master
where eventdate like '%#yr#%'
</cfquery>
Where year is like 2015 - I can easily get year.
But when I switch to:
where eventdate like '%1/%'
I get a Syntax FROM error - I can't get only January. Likely simple solution - but I'm missing it.
Thx for any help.

Use real dates, in a sane format.
yyyy-mm-dd is pretty much the only sane date format, whereas mm/dd/yyyy is pretty much the most insane date representation out there. Don't use that representation for any purpose except end user output.
<cfset date = Now()> <!--- or some other actual date -->
<cfset dtfrom = DateFormat(date, "yyyy-mm-01")>
<cfset dtuntil = DateFormat(DateAdd("m", 1, dtfrom), "yyyy-mm-01")>
<cfquery name="f" datasource="ds">
select * from master
where eventdate >= '#dtfrom#' and eventdate < '#dtuntil#'
</cfquery>
The advantage of using this form >= ... and < ... is that if you have an index on eventdate, it can be used for that. Almost every other variant of expressing the same condition (for example Month(eventDate) = ...) can't use an index.

You escape special characters in access using brackets like so:
WHERE evendate LIKE '%1[/]%'
Also, if your field is an actual DATE (doesn't sound like it) you can tease it out with month() as in:
WHERE MONTH(eventDate) = 1
You might also be able to convert/cast your character field into a data using ASDATE like so:
WHERE MONTH(asDate(eventdate)) = 1
There's the limit of my ancient access experience. good luck. :)

You can use the Format method available in Access.
Try this: Format([eventdate],"yyyy/mm/dd") or if you just want the month and don't care about the year, your query could look like this:
select * from master
where Format([eventdate],"mm") = 1

Related

ColdFusion 11 DateFormat

I am moving one of our applications from ColdFusion 9.01 to ColdFusion 11 and encountered a situation where I cannot get the date formatted the way I want it using "DateFormat". I read through the docs since things have changed in CF versions, but I honestly can't figure out why this isn't working. It worked beautifully in CF 9. I know it's probably something very easy, but I am just not seeing it.
The query (Oracle DB) provides me a list of the last 30 days and the loop is simply to reformat the date output from "2014-07-01 00:00:00.0" to a more friendly looking display of 01-Jul-2014 except that I cannot get it to format as "dd-mmm-yyyy" it just spits back the original output from the query. I hard coded the date where normally there would be a cfquerparam. Any ideas?
<cfquery name="qryDateArray" datasource="#request.db#">
select trunc(to_date('07/01/2014', 'mm/dd/yyyy') + 1 - rownum) as ref_date
from dual connect by rownum <= 30
</cfquery>
<cfloop from="1" to="#qryDateArray.recordcount#" index="j">
<cfset qryDateArray.ref_date[j] = DateFormat(qryDateArray.ref_date[j], "dd-mmm-yyyy")>
</cfloop>
<cfoutput>
<cfdump var="#qryDateArray#">
</cfoutput>
I could not test this on CF11 since I do not have it handy. I did verify that your code though returns results as you explained when I ran it on my CF10 environment here. So what you can do is add a column to the query object and define it as a varchar and add your formatted data to that. This in turn dumped out the formatted dates.
<cfquery name="qryDateArray" datasource="#request.db#">
select trunc(to_date('07/01/2014', 'mm/dd/yyyy') + 1 - rownum) as ref_date
from dual connect by rownum <= 30
</cfquery>
<cfset aryData = [] />
<cfloop from="1" to="#qryDateArray.recordcount#" index="j">
<cfset ArrayAppend(aryData, DateFormat(qryDateArray.ref_date[j], "dd-mmm-yyyy")) />
</cfloop>
<cfset QueryAddColumn(qryDateArray, "STRDATE", "VarChar", aryData) />
<cfoutput>
<cfdump var="#qryDateArray#">
</cfoutput>
If dependent on the query column names then could use something like Ben's method explained here to do some renaming of the columns: http://www.bennadel.com/blog/357-ask-ben-changing-coldfusion-query-column-names.htm
It'd be great if you'd given us a portable test case rather than one that relies on your database, but I suspect it is because ColdFusion has become more rigid with its type management of query columns.
So CF considers your ref_date column to be of type date, so when you try to put the formatted string back into the query column, CF tries (and succeeds) to convert the string back into a date.
Aside:
I have to wonder why you don't format the data string in the DB from the outset, and just return it the way you need it, rather than returning something else, then looping over the thing to adjust it..?

How do I use cfchart area type to show comments per time period

I'm trying to create an area chart using cfchart, but not sure how to go about it. I'm doing a query of all comments in a table and want to show time period (days or months on x-axis) and output number of comments as they are created. Here's the comment query:
<cfquery name="qGetComments" datasource="#session.datasource#">
SELECT PersonFirstName
, PersonLastName
, PersonZip
, CommentCode
, refTopicID
, tbComment.CommentID
, tbComment.CreateDateTime
FROM tbPerson
JOIN tbComment ON tbPerson.PersonID = tbComment.PersonID
</cfquery>
From here, I'm not sure the values to put in the cfchart to output the area chart the way I want. Something like this?
<cfchart chartWidth="400" show3D="yes">
<cfchartseries type="area" query="qGetComments"
valueColumn="CommentID"
itemColumn="CreateDateTime" />
</cfchart>
A simple way to group the records by date in Server 2008+ above is cast the datetime column to a date. Then use simply use the "CommentDate" column as the chart item and "NumOfComments" for the value:
SELECT CONVERT(DATE, tbComment.CreateDateTime) AS CommentDate
, COUNT(*) NumOfComments
FROM tbPerson INNER JOIN tbComment ON tbPerson.PersonID = tbComment.PersonID
GROUP BY CONVERT(DATE, tbComment.CreateDateTime);
You can make the chart labels a little more user friendly by formatting the date within the SQL (see cast and convert). Just be sure to order the results by the date value, and not the formatted string. Otherwise, the chart labels may not appear in proper chronological order (it is a common mistake):
--- format as: Mon dd, yyyy
SELECT CONVERT(VARCHAR, tbComment.CreateDateTime, 107) AS CommentDateString
, COUNT(*) NumOfComments
FROM tbPerson INNER JOIN tbComment ON tbPerson.PersonID = tbComment.PersonID
GROUP BY CONVERT(VARCHAR, tbComment.CreateDateTime, 107)
ORDER BY CONVERT(DATE, CONVERT(VARCHAR, tbComment.CreateDateTime, 107), 107)
SQLFiddle
As an aside, if HTML charts are an option, you might look into Scott's suggestion. Generally CFChart is fine for simple cases, but once you start to customize the appearance (which invariably happens), you are usually better off using the underlying tools directly.

Coldfusion 10 DateFormat Issue

I am using the DateFormat function to convert dates to this format: yyyy-mm-dd. This is the original format of the date: dd-mm-yyyy. Below is a snippet of the code:
<cfset newdate = #DateFormat(Trim(mydate), "yyyy-mm-dd")# />
The problem is that I get different results for different dates. For example:
If my original date is: 15-05-2013 (dd-mm-yyyy)
The result is: 2013-05-15 (yyyy-mm-dd)
However, if I change the input and:
The original date is: 01-05-2013 (dd-mm-yyyy)
The result is: 2013-01-05 (yyyy-dd-mm)
Any help or guidance as to what is wrong would be highly appreciated.
I disagree with the other answer. The real cause of the problem is that DateFormat is not designed to handle non-US date strings.
The standard CF date functions always use U.S. date parsing rules. That means when you pass in an ambiguous date string, like 01-05-2013, it is parsed according to U.S. English date conventions. In this case, month first ie "mm-dd-yyyy". So the result will always be January 5th, not May 1st.
In some cases you get lucky. With the string 15-05-2013, there is obviously no 15th month, so CF/java must swap the month and day automatically, rather than throwing an error. That is why it seems to handle some dd-mm-yyyy date strings correctly, but not others.
If you want to parse non-US date strings, you should use the LS (Locale Sensitive) date functions instead. However, according to the docs dashes ie "-" are not a standard date separator in most non-US locales: only Dutch and Portuguese (Standard). So you would either need to change the separator OR use one of those two locales when parsing the date:
lsDateFormat( myDate, "yyyy-mm-dd", "pt_PT")
Side note:
As an aside, DateFormat does expect a date object. However, like most functions in CF it is flexible enough to accept a date string as well. That allows you to use it as a lazy shortcut to convert from date string => date object => then back to (formatted) date string again. Using date objects is preferable (and you really should validate date strings as well) but that is another conversation altogether ...
The problem is that DateFormat expects a date object, and returns a string.
You're passing it a string, not a date. What you want to do is firstly turn your string (of 01-05-2013 etc) into a date object.
To do this I'd recommend using either ParseDateTime or LSParseDateTime, and/or LSDateFormat.
e.g.
<cfset originalDateString = "01-05-2013">
<!--- turn that into a Date --->
<cfset dateObject = ParseDateTime(originalDateString)>
<cfset newdateString = DateFormat(dateObject, "yyyy-mm-dd")>
Alternatively, if you know your string is always in a dd-mm-yyyy format, you could parse the string yourself, e.g. treat it as a list delimited by hyphens.
<cfset dd = listFirst(originalDateString, "-")>
<cfset mm = listGetAt(originalDateString, 2, "-")>
<cfset yy = listLast(originalDateString, "-")>

How do you calculate DST?

I want to send notifications to users in different timezones on a date and time they provide.
I haven't implemented anything yet, but I plan to create a timestamp column and store everything in UTC. At the time of submission, the user will select a timezone and I will calculate the offset, add it to the timestamp column, and voila.
I wish it were that simple, but my plan lacks DST. I have no way of finding out if the user is in DST or not.
How do I get around this? Do I need extra columns? Is there a better approach than what I'm planning?
You can use the java TimeZone object.
<cfset tzObj = createObject("java","java.util.TimeZone") >
You can get a list of available IDs e.g. "US/Pacific" by doing this
<cfset tzList = arrayToList(tzObj.getAvailableIDs()) >
If you can match the ID to your users region/time zone you can do the following:
tzToTest = "US/Pacific"
dateTotest = now()
<!--- determines if dateTotest in tzToTest is in DST --->
<cfset tz = tzObj.getTimeZone(tzToTest) />
<cfset isDaylightSavings = tz.inDaylightTime(dateTotest) />

Use count() function in ColdFusion query of query

I wanted to use count() function in ColdFusion Query object.
Here is my code and test:
<cfset x = querynew("id,name")>
<cfquery name="y" dbtype="query">
select count(*) as total from x
</cfquery>
<cfoutput>Test1: #y.total#</cfoutput>
<cfset temp = QueryAddRow(x)>
<cfset Temp = QuerySetCell(x, "id", 1)>
<cfset Temp = QuerySetCell(x, "Name", "Vikas")>
<cfquery name="y" dbtype="query">
select count(*) as total from x
</cfquery>
<cfoutput>Test2: #y.total#</cfoutput>
Should I use convert function? Like if total is [enpty string] then result should be 0.
Or is there any other best/proper way to do that?
It does seem like this is a bug, however there is an easy way around it. Simply wrap the y.total in val(), so it would read:
<cfoutput>Test1: #val(y.total)#</cfoutput>
<cfoutput>Test2: #val(y.total)#</cfoutput>
val() will return 0 if an empty string is passed to it.
I think you've found a bug in CF here (perhaps log it # http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html).
The first query should return 0, not [nothing]!
In your simple example, I think just dispense with the QoQ entirely, and just use x.recordCount.
But obviously this is not much chop if you have a WHERE filter in your QoQ, in which case You're gonna need to do something like you suggest. I can't see a better approach here.
If you raise that bug with Adobe, let us know the bug ref so we can vote for it ;-)
--
Adam
If you just want the number of rows in de query-object use: #x.recordcount#