Checking a date is between two dates - coldfusion

In ColdFusion I can see the code below, however it does not seem to work. I want to make sure discount is only applied if the valid from and to dates are in range, see below.
if (
DATEDIFF("d", discount.ValidFrom(), now()) >= 0
AND
DATEDIFF("d", now(), discount.ValidTo()) <= 0
){
// ALL OK Accept Discount
}
else
{
// Discount is no Longer Valid boo!
}

Try this:
Today = Int(Now());
if ( Today GTE Int(discount.ValidFrom())
AND Today LTE Int(discount.ValidTo())
)
{
// discount is valid
}
else
{
// no longer valid
}
It works because datetimes are basically just numbers - with the integer/whole part being the days and the decimal/fraction part being the time.
So applying the Int function will convert a datetime to a whole day date, and then you can just do a simple numeric comparison to ensure it is within the ranges.
I find this far more readable and understandable than the DateDiff stuff - there's no confusion over the ordering of things, which I think is the problem with your provided code snippet (you've switched both order and lte/gte; you only wanted to change one or the other).

Your logic is a bit off. Right now you're returning
if ({positive_number} and {negative_number})
which returns false. You should be checking if dateDiff("d", today, discount.to()) is also >= 0.
<cfscript>
local = {};
local.start = createDate( 2011, 10, 01 );
local.end = createDate( 2011, 10, 30 );
local.today = now();
local.valid = false;
if ( (dateDiff("d", local.start, local.today) >= 0)
AND (dateDiff("d", local.today, local.end) >= 0) ){
local.valid = true;
}
</cfscript>
<cfoutput>
x < z: #dateDiff("d", local.start, local.today) GTE 0#
<hr />
z < y: #dateDiff("d", local.today, local.end) GTE 0#
<hr />
Valid: #local.valid#
</cfoutput>

Related

How to delete a row, if condition on a date is met, through script (half solved)

I have soma data, starting from A10 to column M, until the 59th row.
I have some dates in column F10:F that are text strings, converted to official dates in column N (here the question with the process)
M3 is set to =NOW().
In cell N3 I have: =M3+14.
I want to delete all the rows, with a date in column N10:N that comes before [today + 2 weeks] (so cell N3).
When I create a script in Apps Script, it doesn't run the if statement, but if I leave it in comments, it can go in the for loop and deletes the rows, so I'm pretty sure the problem is, again, date formatting.
In this question I ask: how do I compare the values of N10:N with N3, in order to delete all the rows that don't meet the condition if(datesNcol <= targetDate)? (in code is written as if (rowData[i] < flatArray))
I leave also a demo sheet with this problem explained in detail and two alternatives (getBackground condition and numeric days condition).
Attempts:
This is a simplified code example:
const gen = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Generatore');
const bVals = gen.getRange('B10:B').getValues();
const bFilt = bVals.filter(String);
const dataLastRow = bFilt.length;
function deleteExpired() {
dateCorrette(); //ignore, formula that puts corrected dates from N10 to dataLastRow
var dateCorrect = gen.getRange(10,14,dataLastRow,1).getValues();
var targetDate = gen.getRange('N3').getValues();
var flatArray = [].concat.apply([], targetDate);
for (var i = dateCorrect.length - 1; i >= 0; i--) {
var rowData = dateCorrect[i];
if (rowData[i] < flatArray) {
gen.deleteRow(i+10);
}
}
};
If run the script, nothing is deleted.
If I //comment the if function and the closing bracket, it delets all the rows of the list one by one.
I can't manage to meet that condition.
Right now, it logs this [Sun Jan 01 10:33:20 GMT-05:00 2023] as flatArray
and this [Wed Dec 21 03:00:00 GMT-05:00 2022] as dateCorrect[49], so the first row to delete, that is the 50th (is correct for all the dateCorrect[i] dates).
I tried putting a getTime() method in the targetDate variable, but it only functions if there is the getValue() method, not getValues(), so I then don't know how to use getTime() method on rowData, which is based on dateCorrected[i], which have to use the getValues() method. And then it also doesn't accept the flatArray variable, that has to be commented out (or it logs [ ] for flatArray, not the corrected date)
I leave the other attempts in the demo sheet, because I want to prioritize this problem around the date and make it clear in my head.
Thanks for all the help.
DEMO SHEET, ITA Locale time
I don't know how the demo sheet works with Apps Script, I suggest to copy the code in a personal sheet
UPDATE:
I've also tried putting an extra column, with an IF built-in function that writes "del" if the function has to be deleted.
=IF(O10>14;"del";"")
And then
var boba = gen.getRange(10,16,bLast,1).getDisplayValues();
.
.
if (boba[i] == 'del')
This does the job. But I can't understand why the other methods don't work.
Try this. It seems like you do a lot of things that aren't necessary. Unless I'm missing something.
A few notes. I typically do not use global variable, unless absolutely necessary. I don't create a variable for last row unless I have to use that value multiple times in my script. I use the method Sheet.getLastRow(). dataCorrect is a 2D array of 1 column so the second index can only be [0]. And getRange('N4') is a single cell so getValue() is good enough.
function deleteExpired() {
const gen = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Generatore');
var dateCorrect = gen.getRange(10,14,gen.getLastRow()-9,1).getValues();
var targetDate = gen.getRange('N3').getValue();
for (var i = dateCorrect.length - 1; i >= 0; i--) {
if (dataCorrect[i][0] < targetDate) {
gen.deleteRow(i+10);
}
}
}
Try this:
function delRows() {
const ss = SpreadsheetApp.getActive();
const gsh = ss.getSheetByName('Generatore');
const colB = gsh.getRange('B10:B' + gsh.getLastRow()).getValues();
var colN = gsh.getRange('N10:N' + gsh.getLastRow()).getValues();
var tdv = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate() + 14).valueOf();//current date + 14
let d = 0;
colN.forEach((n, i) => {
if (new Date(n).valueOf() < tdv) {
gsh.deleteRow(i + 10 - d++);
}
});
}

Coldfusion Dynamic Variable (?) parsed to SQL Query

This is the first time I am attempting to parse a variable to a CF query, but I have run into a few little issues.
In summary, I am creating a pivot table of sales by operators by week. Manually, no hassle, but I only want a subset of weeks, not all. Again, no real problem if I want hardcoded weeks, but the problem comes in when I try and parse a week number to the SQL query to create the subset of dynamic weeks.
The CFDUMP shows me that the query is executing based on what I am sending to it, but when it comes to outputting the value of the field (the week), it takes the variable name value, and not the field value if that makes sense?
I know that I shouldn't be having field names as values, but I still tryingh to test right now. With the manual query, I prefix the week number with a 'W' e.g. W9, but when I try and do that I get
MANUAL QUERY
SELECT UserName,
ISNULL([W6], 0) AS [W6],
ISNULL([W7], 0) AS [W7],
ISNULL([W8], 0) AS [W8],
ISNULL([W9], 0) AS [W9],
ISNULL([W10], 0) AS [W10]
FROM ( SELECT CASE
WHEN SUBSTRING(Username, 1, 3) = 'd.S' THEN 'DS'
WHEN SUBSTRING(Username, 1, 3) = 'p.R' THEN 'PR'
WHEN SUBSTRING(Username, 1, 3) = 'j.G' THEN 'JG'
WHEN SUBSTRING(Username, 1, 3) = 'b.c' THEN 'BC'
ELSE 'Other' END AS Username,
CONCAT('W', DATEPART(isowk, ERCFullAuditDate)) as XWeek,
COUNT(1) [SalesCount]
FROM [ERC-Transactions].[dbo].[ERC-Audit]
WHERE ( ERCModule = 'Carriage Return on Account'
AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE())
OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE()))
and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE()))))
GROUP BY DATEPART(isowk, ERCFullAuditDate),
UserName) ST
PIVOT ( SUM(SalesCount)
for XWeek in ([W6], [W7], [W8], [W9], [W10])) as StorePivot
The above yields this result.
THE COLDFUSION DYNAMIC QUERY
Now when I try and do the same, but by parsing variables to the query, the CFDUMP yields the correct values, but as I said, when I try and output this, I get the field name and not the value.
To be honest, I have two issues here in that I need to address. The variable field name, but also when I come to adding the concatenation of 'W' to the week number, I am seeing an 'Error converting data type nvarchar to int.' I think I may need a cfqueryparam, but I am not sure.
<cfset WEEK_2 = DATETImeFormat(DateAdd("ww",-2,now()),"w")>
<cfoutput>Week: #WEEK_2#</cfoutput> (This is the value of the WEEK_2 variable)<br>
<cfset XX = "">
<cfset XX = XX & "SELECT UserName, ">
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
<cfset XX = XX & "FROM ( SELECT CASE ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'd.S' THEN 'DS' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'p.R' THEN 'PR' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'j.G' THEN 'JG' ">
<cfset XX = XX & "WHEN SUBSTRING(Username,1,3) = 'b.c' THEN 'BC' ">
<cfset XX = XX & "ELSE 'Other' END AS Username, ">
<cfset XX = XX & "DATEPART(isowk, ERCFullAuditDate) as XWeek, ">
<cfset XX = XX & "COUNT(1) [SalesCount] ">
<cfset XX = XX & "FROM [EBS-ERC-Transactions].[dbo].[ERC-Audit] ">
<cfset XX = XX & "WHERE ( ERCModule = 'Carriage Return on Account' ">
<cfset XX = XX & "AND ERCFullAuditDate >= DATEADD(week, -4, GETDATE()) ">
<cfset XX = XX & "OR ( ERCFullAuditDate <= DATEADD(week, -52, convert(datetime, GETDATE())) ">
<cfset XX = XX & "and ERCFullAuditDate >= DATEADD(week, -56, convert(datetime, GETDATE())))) ">
<cfset XX = XX & "GROUP BY DATEPART(isowk, ERCFullAuditDate), ">
<cfset XX = XX & "UserName) ST ">
<cfset XX = XX & "PIVOT ( SUM(SalesCount) ">
<cfset XX = XX & "for XWeek in ([#WEEK_2#])) as StorePivot ">
<cfquery name = "QueryTest" dataSource = "EBSERC">
#PreserveSingleQuotes(XX)#
</cfquery>
<br>
<cfoutput Query="QueryTest">
#UserName#, #WEEK_2#<br>
</cfoutput>
<br>
<cfdump var="#QueryTest#" />
And this is the result ...
Ultimately, as mentioned before, I want to concatenate 'W' to the week number field.
Any guidance or a steer in the right direction will be VERY appreciated and thanks for your time.
Thank you very much for reading.
This is too long for comments.
Since the column labels are dynamic and closely bound to the database, I'd probably do this all on the database side. Preferably inside a stored procedure.
If you're using SQL Server 2017+, a CTE could be used to generate the weeks within the desired date range. Then STRING_AGG() used to convert the results into comma separated lists.
; WITH dates AS (
-- Generate range between -56 and -52 weeks ago
SELECT DateAdd(wk, -56, GETDATE()) AS WeekDate
UNION ALL
SELECT DateAdd(wk, 1, WeekDate)
FROM dates
WHERE DateAdd(wk, 1, WeekDate) <= DateAdd(wk, -52, GETDATE())
)
, dateLabels AS (
-- extract week number and construct label "W1","W2",etc..
SELECT DATEPART(isowk, WeekDate) AS WeekNum
, QUOTENAME( CONCAT('W', DATEPART(isowk, WeekDate) )) AS WeekLabel
FROM dates
)
-- convert to comma separated lists
SELECT STRING_AGG( WeekLabel, ',')
WITHIN GROUP (ORDER BY WeekNum) AS PivotColumns
, STRING_AGG( CONCAT('ISNULL(', WeekLabel, ',0) AS ', WeekLabel ), ',')
WITHIN GROUP (ORDER BY WeekNum) AS SelectColumns
FROM dateLabels
;
The results would look like this (minus any line wrapping)
PivotColumns
SelectColumns
[W6],[W7],[W8],[W9],[W10]
ISNULL([W6],0) AS [W6],ISNULL([W7],0) AS [W7],ISNULL([W8],0) AS [W8],ISNULL([W9],0) AS [W9],ISNULL([W10],0) AS [W10]
Then simply plug the two lists into the SQL query. In CF:
<cfscript>
// ...
sqlString = "
SELECT UserName
, #SelectColumns#
FROM (
...
) ST
PIVOT
(
SUM(SalesCount)
FOR XWeek IN ( #PivotColumns# )
) AS StorePivot
";
qPivot = queryExecute( sqlString );
// ...
</cfscript>
Results:
SELECT UserName
, ISNULL([W6],0) AS [W6]
, ISNULL([W7],0) AS [W7]
, ISNULL([W8],0) AS [W8]
, ISNULL([W9],0) AS [W9]
, ISNULL([W10],0) AS [W10]
FROM (
...
) ST
PIVOT (
SUM(SalesCount)
FOR XWeek IN (
[W6],[W7],[W8],[W9],[W10]
)
) AS StorePivot
WHERE oh where are the parentheses?
A few observations about the original query:
The current WHERE clause is incorrect. When mixing AND/OR operators, parentheses must be used to ensure the order of operations. Conceptually, the current query is doing this:
WHERE Condition1 AND Condition2 OR Condition3
It should be using parentheses here:
WHERE Condition1 AND ( Condition2 OR Condition3 )
GETDATE() already returns a datetime value, so there's no need to convert it to a datetime again here:
DATEADD(week, -52, convert(datetime, GETDATE()))
Lastly, there shouldn't be a need for all the concatenation. Strings can usually span multiple lines, and there's always cfsavecontent if needed. Removing all the & will greatly improve readability.
If you're trying to copy the SQL exactly I think you missed the 'W' in the cfset at the top:
<cfset WEEK_2 = 'W' & DATETImeFormat(DateAdd("ww",-2,now()),"w")>
Outputs:
Week: W9 (This is the value of the WEEK_2 variable)
You have this command:
<cfset XX = XX & "ISNULL([#WEEK_2#], 0) AS [#WEEK_2#] ">
Since the week_2 variable has a value of 9, when that command gets executed, it becomes this:
<cfset XX = XX & "ISNULL([9], 0) AS [9] ">
and your query becomes
select username
, 9 as 9
from etc
You are going to have to put some more thought into generating your week numbers.

Power BI: Multiple condition in single if condition

I have table with the fields Amount, Condition1, Condition2.
Example:
Amount Condition1 Condition2
----------------------------------
123 Yes Yes
234 No Yes
900 Yes No
I want to calculate the 20% of the amount based on condition:
If both Condition1 and Condition2 is Yes then calculate 20% else 0.
My try: I tried with conditional custom column but unable to add AND in IF in the query editor.
You can write a conditional column like this:
= IF(AND(Table1[Condition1] = "Yes", Table1[Condition2] = "Yes"), 0.2 * Table1[Amount], 0)
Or you can use && instead of the AND function:
= IF(Table1[Condition1] = "Yes" && Table1[Condition2] = "Yes", 0.2 * Table1[Amount], 0)
Or an even shorter version using concatenation:
= IF(Table1[Condition1] & Table1[Condition2] = "YesYes", 0.2 * Table1[Amount], 0)
Try to create a new calculated column.
And Use below DAX query:
new_column = IF(Conditition1 = "Yes", IF(Condititon2 = "Yes",Amt * 0.2 ,0), 0)

How to validate dates in Hash format in MySQL or C++

I need to validate dates in Hash (SHA256) format in MySQL or C++.
For example: date1 < date2 or date1 > date2.
I have this query in MySQL:
SELECT SHA1(CURDATE()) -->'2017-09-06'
and:
SELECT SHA1('2017-09-06') --> '34152f3661d73490ac89b0fe15cb3170aac06bb8'
SELECT SHA1('2017-09-07') --> '0b10f03fb245a6486d6ab5b25a2f050bf87093a5'
But, if I use:
SELECT IF (SHA1('2017-09-06') <= SHA1('2017-09-07') ,'True','False') AS Test;
the result is False, therefore, incorrect!
Don't know why you'd do this, but here's a solution for you.
Here's some assumptions.
You were given two date hashes (two inputs)
You know exactly how the date hashes were created (EG: always in the format of YYYY-MM-DD)
You know the range of your target date (So you can reverse the hash back to the original date)
So in psudocode, you'd do something like this.
date getDateFromHash(string inputHash) {
date startDate = '1911-01-01';
date endDate = '2017-12-31';
for(date checkDate = startDate; checkDate < endDate; checkDate + 1 day) {
if (sha1(checkDate) = inputHash) { return checkDate }
}
return null;
}
date firstDate = getDateFromHash("0b10f03fb245a6486d6ab5b25a2f050bf87093a5"); // 2017-09-07
date secondDate = getDateFromHash("34152f3661d73490ac89b0fe15cb3170aac06bb8"); // 2017-09-06
if (firstDate > secondDate) {
return true;
} else {
return false;
} // compare using default date operators
But honestly speaking, like the comment says, there's no point of hashing date values. Hence why I'm only dropping a quich psudo code for you just to point you in the right direction, if you seriously want to tread down this path.

Using ng-pattern with ng-model parsing/formatting

I'm trying to be real fancy with angular inputs by using both ng-pattern and ng-model parsing together. The regex I put in ng-pattern works fine on regex101.com, and even logging it in my app it works great. When using it in ng-pattern however, its saying my input is invalid though when it should not be. I'm wondering when ng-pattern does its thing in relation to when ngModel.$parsers/ngModel.$formatters are doing their thing, because i could see that causing it to fail. Here's some code:
Here's the ngModel parsing directive:
UI.directive('formatSeconds', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
var padZero = function (num, size) {
return ('00' + num).substr(-size);
};
var formatSeconds = function (seconds) {
var min = Math.floor(seconds / 60);
var sec = Math.floor(seconds % 60);
var ms = Math.round(((seconds % 60) - sec) * 1000);
return min + ':' + padZero(sec, 2) + ':' + padZero(ms, 3);
};
var parseTime = function (time) {
time = time.split(':');
var min = parseInt(time[0] || 0);
var sec = parseInt(time[1] || 0);
var ms = parseInt(time[2] || 0);
return min * 60 + sec + (ms / 1000);
};
ngModel.$parsers.push(parseTime);
ngModel.$formatters.push(formatSeconds);
}
};
});
Here's my regex in my controller:
$scope.timeRegex = /^([0-9]+)?\:([0-5][0-9])\:?([0-9]{3})?$/;
And here's the relevant part of my view:
<tbody ng-form name="syncForm">
<tr class="timing-entry" ng-repeat="entry in scenario.syncManifest">
<td>
<input type="text" ng-attr-name="{{'time' + $index}}" required ng-model="entry.time" format-seconds ng-pattern="timeRegex" />
</td>
</tr>
</tbody>
The time in entry is in seconds, so the formatter puts it in 0:00:000 format. Then I hoped the ng-pattern would kick in and say yes! valid! But I'm wondering if it is running when the time property is still in 0.000 format before parsing.
Angular validation is performed upon the ng-model value, that is to say:
When a value is inputted into the view, the $parsers will run and the inputted value will be transformed into how you want it stored in the ng-model. In this case, thats a number representing the number of seconds. Then the ng-pattern will work on that value - if it passes validation, ng-model will be set.
When the value is set from the controller, the ng-pattern will go to work on that raw ng-model value. I believe the $formatters will run and the formatted $viewValue will be sent to the view regardless of the validation result.
Either way - in your example, ng-pattern will be working on the integer value of seconds, not the formatted value displayed in the control.