Determine the amount of clicks required to reach a specific date using a JQuery calendar? - ruby

I have a jquery calendar for the start date of a project.
Using Watir (automated browser driver, a gem for ruby), I have a set date that I would like to enter in.
The calendar start date is always today's date, whatever that may be for the day it is used. I was wondering if there was a way that ruby can process what today's date is, and use the specified date provided by the user, to calculate the difference of months between them.
Here is an example of the Calendar plugin: http://jqueryui.com/datepicker/
example:
today's date is 30/10/2012, if there was a project that were to start on the 20/12/2012, that would be 2 months from now, so 2 clicks on the next month button.
Is there a way I could do this?

Here is how I approached a similar situation with JSdatepicker:
$today = Time.now.strftime("%e").gsub(" ", "") #one digit day of month without leading space
#browser.text_field(:id => /dateAvailable/).click
Watir::Wait.until(60) {#browser.div(:id => /dateAvailable_popup_cal/).td(:text => $today).exists?}
#browser.div(:id => /dateAvailable_popup_cal/).td(:text => $today).click
Set or grab the date.
Click the text_field that fires the JSDatePicker object
Wait until the calendar actually pops up
The current month is shown, so choose today's date number.
In your case, you also need to set the month. Whether prompting the user for this, or choosing "today", the theory is the same:
$month = Date::MONTHNAMES[Date.today.month] #etc
Pseudo-code making lots of assumptions (only future dates, month name shown on calendar as text, etc):
while !#jquerytablewindow.text.include?($month)
next_month_button.click
end
I don't see a specific advantage to my method versus counting each month, unless of course we add a month to the calendar one day and you still want your code to work!

You could do:
#End date converted to date object
specified_date = '20/12/2012'
end_date = Date.parse(specified_date)
#Start date (today - 30/10/2012)
today = Date.today
#Determine difference in months
number_of_months_up_to_today = (today.month + today.year * 12)
number_of_months_up_to_end = (end_date.month + end_date.year * 12)
clicks_required = number_of_months_up_to_end - number_of_months_up_to_today
#=> 2
Basically it is counting the number of months since the year 0 and then finding the difference.

Related

LUA credit card expiry date validation

I have an application collecting credit card data. Before sending the information out to the payment entity I am trying to make sure the information entered is, at least, valid. I already worked out the card number and cvv numbers but I am not so sure about the expiry date. The format I get the info is MMYY. So what I am doing is:
-- Simple function to get current date and times
function getdatetime(tz)
local tz = tz or 'America/New_York';
local luatz = require 'luatz';
local function ts2tt(ts)
return luatz.timetable.new_from_timestamp(ts);
end
local utcnow = luatz.time();
local time_zone = luatz.get_tz(tz);
local datetime_raw = tostring(ts2tt(time_zone:localise(utcnow)));
local year, month, day, hour, min, sec, time_reminder = string.match(datetime_raw, "^(%d%d%d%d)%-(%d%d)%-(%d%d)[Tt](%d%d%.?%d*):(%d%d):(%d%d)()");
return year, month, day, hour, min, sec;
end
local current_year, current_month = getdatetime() -- Get current year/Month
local card_expiry_date = 'YYMM'; -- In the app this actually get a value eg: 2204, 2301, 2010, etc.
local card_exp_year = string.sub(card_expiry_date , 3, 4)
local card_exp_month = string.sub(card_expiry_date , 1, 2)
-- Extract the last two digits of the Year
current_year = string.sub(current_year , 3, 4)
-- Check month is valid
if(card_exp_month < '01' or card_exp_month > '12')then
print("This is not a valid month")
else
-- Check date is this month or after
if((card_exp_year < current_year) or (card_exp_year == current_year and card_exp_month < current_month))then
print("Date cannot be before this month.")
else
print("All is good.")
end
end
I do not know if this is the most elegant solution but it works. However it has a huge bug: it will fail at the end of the century. Since I only know the last two digits of the expiry date year, if a card expires in 2102 for instance and we were in 2099 my logic would wrongly reject the date (02 is less than 99).
I am very aware that me an my simple app will likely not be around by then but it bugs me to leave it like this.
Can anyone please suggest a proper way to do this validation?
Thank you!
Wilmar
Credit cards usually expire within a few years. 3 years is average according to some quick web search. Also the owner of a century only card can be safely assumed to be dead and so is his card account.
So when you get a card with 02 in 2099 there is only one reasonable option.
Calculate two differences and pick the smaller one.
Something like local expiresIn = math.min(math.abs(99-2), math.abs(99-102))

Can't get monthy CarbonPeriod to behave as desired

In the project I'm working on I have a daily command that basically checks the date of the last record in the database and tries to fetch data from an API from the day after and then each month after that (the data is published monthly).
Basically, the last record's date is 2019-08-30. I'm mocking as if I were running the task on 2019-09-01 with
$test = Carbon::create(2019,9,1,4);
Carbon::setTestNow($test);
I then create a monthly period between the next day of the last record's date and the last day of the current month like so:
$period = CarbonPeriod::create($last_record_date->addDay(), '1 month', $last_day_of_current_month);
Successfully generating a period with start_date = 2019-08-31 and end_date = 2019-09-30. Which I use in a simple foreach.
What I expected to happen is that it runs twice, once for August and once for September, but it's running only once for the start date. It's probably adding a month and going past the end date, but I don't know how to force the behaviour I'm looking for.
TL;DR:
$period = CarbonPeriod::create('2019-08-31', '1 month', '2019-09-30');
foreach ($period as $dt) {
echo $dt->format("Y-m") . "<br>\n";
}
This will print just 2019-08, while I expect 2019-08 and 2019-09. What's the best way to achieve that?
Solution :-
You can store actual date in $actual_day and current date for occurring monthly in $current_day. Put a check on comparing both dates, if not matched then make it on the same day it will skip 30,31 case in case of February month.
$current_date = $current_date->addMonths(1);
if($current_date->day != $actual_day){
$date = Carbon::parse($date->year."-".$date->month."-".$actual_day);
}
Your start date is 2019-08-31. Adding a month takes you to 2019-09-31. 2019-09-31 doesn't exist so instead you get 2019-10-01, which is after your end date. To avoid this I'd suggest you use a more regular interval such as 30 days.
Otherwise you're going to have to rigorously define what you mean by "a month later". If the start date is 31st Jan is the next date 28th February? Is the month after 28th or 31st March? How do leap years affect things?

Convert DDMON (eg. 23JAN) date format to full date with correct year applied in Ruby

Am looking for a compact solution for converting the dates that come from the airline reservation systems (GDS like Sabre/Galileo/Amadeus) which dont have the year - eg. 23JUN to a standard date, but need to determine the year quickly to tack on in Ruby. (FYI - on these systems date can only be max 355 days from today. So there is no ambiguity of interpreting 12MAY as 2013-05-12 instead of 2012-05-12 assuming today is 12MAY 2012). If today is 25th Dec 2012, and date is entered as 01JAN, this would be 01JAN2013 in the future, and if today is 21JUL 2012, input date of 01JAN would also become 01JAN 2013 as it is a past date in the current year.
So I can do something like:
t = DateTime.now
crsdate = DateTime.strptime("23JAN","%d%b")
if crsdate >= t
# Year is current year
else
# Year is next year
end
Is there a more elegant way of doing this?
How about this?
t = DateTime.now
crsdate = DateTime.strptime("23JAN","%d%b")
crsdate >= t ? crsdate >>= 12 : crsdate
If you don't need to modify crsdate because you just want to return this, use >> instead of >>=.

Return date if within date range

I have an object which contains a list of due dates, I am trying to build a system which returns the due date when a specified date is 1 month or less before the due date. It should return the due date in this format "1st Feb 2009". Let me clarify, using my current code
#Build array of estate objects
estate.due_dates = "1st Feb, 3rd May, 1st Aug, 5th Nov"
estate2.due_dates = "28th Feb, 31st May, 31st Aug, 30th Nov"
estates = [estate,estate2]
set_due_date_on_estates("1st Jan 2009",estates) #Run function - should return "1st Feb 2009,28th Feb 2009"
def set_due_date_on_estates(date,estates)
estates.each{|estate|
estate.due_dates.split(",").each{|due_date|
((date)..(date >> 1)).each{|current_date|
estate.set_reminder(due_date + current_date.strftime("%Y")) if current_date.strftime('%d %m') ==
Date.parse(due_date).strftime('%d %m')
}
}
end
}
The issue I am having, is that my list of due dates doesnt have a Year, so I am looping through my range and checking if the dates are equal using the format "%d %m". If so I am setting the reminder in the estate object by using the current "due date" in the loop concatenated with the Year of the "current date" in the loop.
Am not too happy with the code, in particular the nested loops and wondered if there was a better way I could deal with checking that the due_dates where in the date range, even though the due_dates dont have a year. Thanks
You could use date parsers: Kronos, chronic
Example for kronos:
def parse_date(date)
Kronos.parse(date.sub(/\d{4}$/, ''))
end
This function gives you a Kronos object without year which is more easily to compare, build range and so on.
Yes you can use Chronic and also you can write a worker which will keep checking if the specified date is 1 month or less before the due date at regular interval. And ask that worker to do something if result is true (say send you an email or anything if date is within due date) you can find more information about worker by googling Resque and Redis. Another option would be to convert both dates on some base reference and then do the calculations.

How do I dynamically select parameter with crystal report

I have been working on getting a report out for long without success.
I have a report that select based on parameter fields of date and boolean. Currently I have to create 3 reports. One based on dates, one based on the boolean and one based on both.
However, I want my report to be able to select all dates if the user does not input date in the parameter or select all booleans if user does not select one.
Currently I used this
if ({?Start Date} = DateTimeValue('') or {?End Date} =DateTimeValue('')) then
{rectReport.Call date} in DateTimeValue ('1753-01-01 00:00:00') to CurrentDateTime
else
({rectReport.Call date} in {?Start Date} to {?End Date}) and {rectReport.EngineDown} = {?Engine Down}
The basic Idea I am looking for is that the user can decide to select only one parameter instead of the two.
Any help will be highly appreciated.
Thanks,
Bimbo
In Crystal 2008 you have the option of making parameters optional. What you could do is create one report with both parameters and then set both parameters as optional. In your record selection formula you could do something like this:
(if (HasValue({?Startdate}) and HasValue({?Enddate}))
then {table.datefield} in {?Startdate} to {?Enddate}
else {table.datefield} in {defaultstartdate} to {defaultenddate})
and (if HasValue({?BoolParam}) then {table.boolfield} = {?BoolParam}
else {table.boolfield} = {defaultbool})
If you wanted to select ALL tables if the user did not input the parameter, you could just omit the else-statements.
(note: Sorry if that syntax isn't correct (I am just getting back into CR again), but you get the idea.)
EDIT: Since optional parameters aren't available in CR10, couldn't you just use parameter default values for the dates instead? For the boolean, you could just make a parameter with 3 values: true, false, and "all" and then default to the "all" value when running the report.
I don't know your particular situation, but the way we handle this (specifically for Defined Periods vs User-specified-Date-Range) is through being able to set defaults.
Our main environment is BOE XI.
Our parameters might be
ReportPeriod (String Variable)
and
CustomDates (DateTime Range, but will work as two discrete dates)
Example params for ReportPeriod might be
1 Day
7 Days
Last Month
Custom Dates
Formulas are used to calculate date limits that will be used in the record selection. I start with the END DATE, as it is convenient for our period reports.
#EndDate
Select ?ReportPeriod
Case
"1 Day", "7 Days" : CurrentDate
// Conveniently defaults to MIDNIGHT
"Last Month" : Maximum(LastFullMonth)
"CustomDates" : Maximum(?CustomDates)
// Or discrete parameter for end date
default : CurrentDate
#BeginDate
Select ?ReportPeriod
Case
"1 Day" : DateAdd("d", -1, #EndDate)
"7 Days" : DateAdd("d", -7, #EndDate)
"Last Month" : Minimum(LastFullMonth)
"CustomDates" : Minimum(?CustomDates)
// Or discrete parameter for end date
default : DateAdd("d", -1, #EndDate)
And, let me caution against using CurentDateTime unless necessary. Every time you try to step through the report, the selection will have changed: 5:01:10 PM ... 5:01:16 PM ... 5:01:24 PM ...
When publishing a report, we set default date (it doesn't matter what, it's only used for CUSTOM and the customer resets it then), and a default ReportPeriod.
The report can be scheduled periodically (based on ReportPeriod) and it will always run.
If the user wants to do custom dates (historic reporting, etc.), then they can chose that for report period, and then set whatever start and end dates they need.
Helpful?

Resources