Getting Min and Max dates from available list of dates - coldfusion

I have dates as a list in the following format:
09-2012,10-2012,01-2013
What will be the better way to access the minimum and maximum dates from the list?

I'm not really sure which is faster. Here is my list-only-solution below , or you could convert the list to an array and work with that.
This does the job though:
<CFSET dates = "" />
<CFLOOP list="09-2012,10-2012,01-2013" index="date">
<CFSET dates = listappend(dates,DateFormat(createDate(listlast(date,"-"),listfirst(date,"-"),1), "yyyy-mm-dd")) />
</CFLOOP>
<CFSET dates = listsort(dates,"numeric") />
<CFSET min_date = listfirst(dates) />
<CFSET max_date = listlast(dates) />

I would recommend transforming the dates in the list to yyyy-mm-dd.
Then you can just sort the list with ListSort and you will get the first and last date by listfirst and listlast

Similar to Seybsen's answer, only going down the regex path:
<cfscript>
var data = "09-2012,10-2012,01-2013";
data = listSort( reReplace( data, '([0-9][0-9])-([0-9][0-9][0-9][0-9])', '\2-\1', 'all' ), 'numeric', 'asc' );
var minDate = listFirst( data );
var maxDate = listLast( data );
</cfscript>

I adapted #Seybsen's answer to find the max date from a query without doing a query of queries:
<cfset maxCompletedDate = ListLast(ListSort(ValueList(queryName.completedDate), "numeric")) />
Thought I would put this out there if anyone else is looking of the same thing but, again, credit #Seybsen.
BTW, the dates in the database where formatted yyyy-mm-dd H:mm:ss. Timestamps like 2013-09-15 18:43:17

Related

group cfdirectory by dateLastModified (date not time)

I am running ColdFusion 9 and Oracle database. I am trying to group all files from a directory by the dateLastModified using:
<cfdirectory action="LIST"
directory="#path_to_files#"
name="res"
sort="datelastmodified desc,name ASC"
filter="#filters#">
For example:
Date of File 1: 2016-10-03 11:49:00 am
Date of File 2: 2016-10-03 07:49:00 am
Date of File 3: 2016-08-03 07:49:00 am
File 1 & 2 should be group 1 and File 3 should be group 2
If I use a query of query, how can I compare the date based on days not time? This is what I have so far but it does not seem to work. I get no records.
<cfquery name="getfiles" dbtype="query">
SELECT name, datelastmodified
FROM res
WHERE CAST( [datelastmodified] as date) = CAST(<cfqueryparam cfsqltype="CF_SQL_DATE" value="#d#"/> as date)
</cfquery>
Does anyone know a different method to group files based on days not time?
method to group files based on days not time
To group by Date (only), add the "date only" column to your SELECT list. Then ORDER BY the new column:
<cfquery name="qSortedFiles" dbtype="query">
SELECT CAST(DateLastModified AS Date) AS DateOnly
, Name
, DateLastModified
FROM getFiles
ORDER BY DateOnly
</cfquery>
<cfoutput query="qSortedFiles" group="DateOnly">
#DateOnly#<br>
<cfoutput>
- #DateLastModified#<br>
</cfoutput>
</cfoutput>
I get no records.
FWIW, the reason is that despite using CAST ... as Date, apparently CF still preserves the "time" portion internally. So the WHERE clause is still comparing apples and oranges:
<!--- comparing Date and Time to Date (only)
WHERE 2016-08-03 07:49:00 am = 2016-08-03 00:00:00 am
Instead of using an equals comparison, use this approach:
WHERE DateLastModified >= {TheStartDateAtMidnight}
AND DateLastModified < {TheNextDayAtMidnight}
This type of comparison is more flexible as it works with both date and time columns - and dates (only).
WHERE CAST(DateLastModified AS Date) >= <cfqueryparam value="#someDate#" cfsqltype="cf_sql_date">
AND CAST(DateLastModified AS Date) < <cfqueryparam value="#dateAdd('d', 1, someDate)#" cfsqltype="cf_sql_date">
Step 1 - Use cfdirectory to get a query object.
Step 2 - Add a column using queryaddcolumn.
Step 3 - Loop through the query. Use querySetCell and dateformat on your new column
Step 4 - use cfoutput, group by your new column, to do what you need to do. Your cfdirectory tag already has the data sorted.
So I figured it out. Thanks to #Dan and #Leigh for their suggestion. I used both as guides to get what I wanted.
I used cfdirectory to get a query object.
I created a new query using QueryNew, QueryAddRow and QuerySetCell.
On the columns of the new query contained the formatted date (mm/dd/yyyy). Make sure that you declare the column as varchar not date when setting the column names QueryNew.
I used cfloop and group option and cfoutput to display the records.
<cfset path_to_files = "d:\inetpub\wwwroot\mailrideli\webrpt\">
<cfset filters = "*.pdf|*.txt|*.xls">
<cfdirectory action="LIST" directory="#path_to_files#" name="res" sort="datelastmodified desc,name ASC" filter="#filters#">
<cfset q = QueryNew("Name,dateformated,datelastmodified, size","Varchar, Varchar, date, varchar")>
<cfset count = 1>
<cfset newRow = QueryAddRow(q,res.recordCount)>
<cfloop query="res">
<cfset d = DateFormat(res.dateLastModified,"mm/dd/yyyy")>
<cfset temp = QuerySetCell(q, "Name", "#res.name#", count)>
<cfset temp = QuerySetCell(q, "dateformated", "#d#", count)>
<cfset temp = QuerySetCell(q, "datelastmodified", "#res.datelastmodified#", count)>
<cfset temp = QuerySetCell(q, "size", "#res.size#", count)>
<cfset count += 1>
</cfloop>
<cfoutput>
<cfloop query="q" group="dateformated">
#q.dateformated#<br />
<table>
<tr>
<th>File Name</th>
<th>Size (bytes)</th>
<th>Last Modified</th>
</tr>
<cfloop>
<tr>
<td>#q.name#</td>
<td>#q.size#</td>
<td>#dateformat(q.dateLastModified, 'mm/dd/yyyy')# #timeformat(q.dateLastModified, 'hh:mm:ssTT')#</td>
</tr>
</cfloop>
</table>
</cfloop>
</cfoutput>
I hope it helps anyone out there.

How to validate the Dateformat Mask using ColdFusion?

How to check the date format using ColdFusion. I want to check that the user enters a date in the format yyyy-mm-dd. When a user enters a date in the format dd-mm-yyyy I want to show an error message. Is there any simple way to solve this?
Do you need to validate the date format from the server side?
Here I've given a simple RegEx check to check the format and did some checks to validate.
<cfset regex = '[0-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]'>
<cfset myDate = '2006-12-39'>
<cfset MatchedDate = REMatchNoCase(regex, myDate)>
<cfif arrayLen(MatchedDate) AND isDate(myDate) AND MatchedDate[1] EQ myDate>
Valid date
<cfelse>
Invalid date
</cfif>
As I said in comment, you can validate it on client side with following function
function validateDate(){
var dt = document.forms["Form_Name"]["Date_Field"].value;
var pattern =/^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})$/;
if (dt == null || dt == "" || !pattern.test(dt))
{
alert("invalid date");
return false;
}
else{
return true
}
}
then in cf code, while processing
<cfset desiredFormat=DateFormat(form.Date_Field,"yyyy-mm-dd")>
ps: the js function was taken from Javascript Date Validation ( DD/MM/YYYY) & Age Checking
You could do this:
<cfinput name="StartDate"
validate="date"
type="text"
maxlength="10"
mask="9999-99-99"
message="Start Date must be a valid date."
required="yes">
The key is the mask attribute. However, if you pre-populate this field, attempting to change the value can become frustrating.

ColdFusion Date Logic

I am embarrassed to admit that I am not the greatest when it comes to dates and date logic ColdFusion.
<!---checks frequency for form schedule and sets datepart. RecordType_Frequency is a column in database daily, weekly, monthly etc.--->
<CFSWITCH expression="#RecordType_Frequency#">
<CFCASE value="Daily">
<CFSET datepart = "d">
</CFCASE>
<CFCASE value="Weekly">
<CFSET datepart = "ww">
</CFCASE>
<CFCASE value="Monthly">
<CFSET datepart = "m">
</CFCASE>
<CFCASE value="Quarterly">
<CFSET datepart = "q">
</CFCASE>
<CFCASE value="Yearly">
<CFSET datepart = "yyyy">
</CFCASE>
</CFSWITCH>
<!---setting dates based on database values for when the form should schedule--->
<!---enddate Uses the RecordType_Frequency_StartDate column from the database which is a date in the past. Coefficient is a stored db value for the frequency 1,2 etc. for could scheduled every 1 year, 2 year --->
<cfset enddate = datediff(datepart,RecordType_Frequency_StartDate,todaydate) + Coefficient>
<!---start date is set to current RecordType_Frequency_StartDate which is a column value from the database--->
<cfset startdate = RecordType_Frequency_StartDate>
<!---sets the next start date for when the for should schedule based on historic db start date--->
<cfset new_date = dateformat(DateADD(datepart,Coefficient,startdate),'MM-DD-YYYY')>
<cfloop from="1" to="#enddate#" index="i">
<cfset new_date = dateformat(DateADD(datepart,Coefficient,startdate),'MM-DD-YYYY')>
<cfset startdate = new_date>
<cfset diff = datediff(datepart,RecordType_Frequency_StartDate,startdate)>
<cfif (startdate GT todaydate)>
<cfset next_date= startdate>
<cfoutput>
<!---I need this output to equal the next date value that would fall based on the schedule, future date. I am seeing multiple dates and need to figure out how to capture would weould truly be the next scheduled date--->
Next Date = #diff# - #dateformat(next_date)#<br />
</cfoutput>
</cfif>
</cfloop>
In summary, I have forms that are on a schedule. The start/set up date is the only date that I have to use. I need to to grab or populate the next scheduled date for the form using what information I have. Obviously the next creation date needs to fall in the future as this date will be used in conjunction with a scheduled event.
I have posted the code with comments and need help grabbing the next logical date closest to the current date that should fall in sequence.
http://cfquickdocs.com/#DateAdd
If all you need is the next possible date, use the dateadd() function.
For example, if you want the next weekday use: dateadd("w", 1, now())
Assuming I understand your problem, then a UDF that I wrote a while back might solve your problem:
http://www.bryantwebconsulting.com/blog/index.cfm/2011/2/24/EnglinshFriendly-Interval-Calculation
Among several other options for the "interval" argument, it should also accept the ones you use in your switch block.

how to store query data in variables in ColdFusion for use later?

I am trying to retrieve and store ID's for each item retrieved from my table, so I can use these ID's later. I tried nesting the queries, but this didn't, work. Here is my first query:
<CFQUERY datasource="MyDSN" name="MAIN2"> SELECT * from order_items where orderID= #orderID#</CFQUERY>
Now, if I output this query it displays, 1 and 117 which are the two ID's I need.
My next query is:
<CFQUERY datasource="MyDSN" name="MAIN3">select c.catalogueID,
c.product_name,
c.product_price,
c.description,
p.productID
from products p
join product_catalogue c on c.catalogueid = p.catalogueid
where p.productid = "#productID#"</CFQUERY>
But it is telling me that productID is not defined, it is obviously empty. I am just getting started using ColdFusion, so I am not sure the best way to store the values I need so I use them again. I also need to loop the second query to run for each ID 1 and 117, so twice.
Any suggestions on how to accomplish this would be greatly appreciated.
Thanks
My basic rule is that if I find myself using queries to create other queries or looping over a query to execute other queries; it is time to consider combining the queries.
I'm not sure what field you are using in the MAIN2 query to feed the MAIN3 query. So, I put in "productID" in the query below. You may have to change it to fit your field name.
<CFQUERY datasource="MyDSN" name="MAIN3">select c.catalogueID,
c.product_name,
c.product_price,
c.description,
p.productID
from products p
join product_catalogue c on c.catalogueid = p.catalogueid
where p.productid IN (SELECT DISTINCT productID from order_items where orderID= <cfqueryparam value="#orderID#" cfsqltype="CF_SQL_INTEGER">)
</CFQUERY>
You could also change this query to utilize a "join" to connect [order_items] to the query.
Lastly, you should use the <cfqueryparam> tag for the where clauses; this helps protect your query from sql injection attacks.
Whenever I'm caching data for use later, I tend to ask myself how I'll be using that data, and whether it belongs in another data type rather than query.
For instance, if I'm wanting a bunch of data that I'm likely to access via ID, I can create a structure where the key is the ID, and the data is another structure of a dataset. Then I'll save this structure in application scope and only refresh it when it needs to be. This is zippy fast and so much easier to grab with
rather than querying for it every time. This is especially useful when the query that creates the original data set is kind of a resource hog with lots of joins, sub-queries, magical cross-db stored procedures, but the datasets returns are actually fairly small.
So creating your products structure would look something like this:
<CFQUERY datasource="MyDSN" name="MAIN3">
SELECT
c.catalogueID,
c.product_name,
c.product_price,
c.description,
p.productID
FROM products p
JOIN product_catalogue c
ON c.catalogueid = p.catalogueid
WHERE p.productid = <cfqueryparam value="#ProductID#" cfsqltype="cf_sql_integer">
</CFQUERY>
<cfset products = structNew() />
<cfset item = structNew() />
<cfloop query="MAIN3">
<cfif NOT structKeyExists(products, productID)>
<cfset item = structNew() />
<cfset item.catalogueID = catalogueID />
<cfset item.product_name = product_name />
<cfset item.product_price = product_price />
<cfset item.description = description />
<cfset products[productID] = structCopy(item) />
</cfif>
</cfloop>
<cfset application.products = structCopy(products) />

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#