How do I allow my model to accept two different date formats? - date

I'm using Ruby on Rails 5. I have the following code in my model ...
class User < ActiveRecord::Base
...
attr_accessor :dob_string
def dob_string
#dob_string || (self.dob ? self.dob.strftime('%m/%d/%Y') : "")
end
def dob_string=(dob_s)
date = dob_s && !dob_s.empty? ? Date.strptime(dob_s, '%m/%d/%Y') : nil
self.dob = date
rescue ArgumentError
errors.add(:dob, 'The birth date is not in the correct format (MM/DD/YYYY)')
#dob_string = dob_s
end
Despite my instructions, sometimes users enter the date in the form MM-DD-YYYY. So what I want to do is allow my model to accept both formats, MM/DD/YYYY or MM-DD-YYYY, but not mixed, that is MM/DD-YYYY shoud still be illegal. How do I modify my model so that it can accept either format?

I think this might do what you need:
class User < ActiveRecord::Base
def dob_string
#dob_string || (dob ? dob.strftime("%m/%d/%Y") : "")
end
def dob_string=(dob_s)
unless convert_preferred_date(dob_s) || convert_acceptable_date(dob_s)
errors.add(:dob, 'The birth date is not in the correct format (MM/DD/YYYY)')
#dob_string = dob_s
end
end
private
def convert_preferred_date(dob_s)
convert_date(dob_s, "%m/%d/%Y")
end
def convert_acceptable_date(dob_s)
convert_date(dob_s, "%m-%d-%Y")
end
def convert_date(dob_s, format)
self.dob = (dob_s && !dob_s.empty? ? Date.strptime(dob_s, format) : nil)
rescue ArgumentError
nil
end
end
It's a little inelegant, but I can't think of a way to do only two date formats. If you're prepared to accept any human-readable data format, there's a much simpler way to do this.
Please test this thoroughly in your own app. I was just messing around with this in the Rails console, and I might not have tested every case. Hopefully this helps.

Related

cant translate text with value using GETX in flutter

the problem is that the text has value which declares the day before the text
so idk how to translate this text that includes value.
untilEventDay =
'${pDate.difference(DateTime.now()).inDays},days/ until event day'
.tr;
in translation page :
,days/ until next event day': 'ڕؤژ ماوه‌/ تاوه‌كو ئیڤێنتی داهاتوو',
you should separate the value's string from your translation
var eventDayCountDownTitle = '${pDate.difference(DateTime.now()).inDays}' + ',' + days/ until event day'.tr;
and if you need your day number to be in a specific language, you can use a map or a helper method. map solution would be something like this:
Map<String,String> englishToPersianNumber = {'1' : '۱'}
and then use it in your string :
englishToPersianNumber[pDate.difference(DateTime.now()).inDays.toString()]
Important: to have a cleaner code, you can create a helper method to generate your desired string, and call it in your text widget. the code would be more understandable that way. Also, you can add handle any conditions that may later be added to the string generator. like if it's the last day, write something else instead of 0 days remaining.
String eventDayCountDownTitle(int remainingDays) {
if(remainingDays == 0) return "Less than One day to the event".tr;
return '${remainingDays.toString}' + ',' + 'days/ until event day'.tr;
}
ps. your question's title is wrong, you should change it to what you're explaining in the caption

pq: date/time field value out of range: "22/02/2022"

I have this query:
l.loyaltycard_number, l.recipt_no,
l.totaltrans_amount, l.amount_paid,
l.reward_points, l.redeemed_points,
cashier FROM loyalty l
JOIN warehouses w
ON l.machine_ip = w.machine_ip
WHERE l.machine_name = $1
AND redeemed_points != $2
AND trasaction_time BETWEEN $3 AND $4
ORDER BY trasaction_time DESC;
I have HTML datepickers for the transaction_time that is in the format dd/mm/yyyy.
anytime I select a date range that the first number is greater than 12, (22/02/2022).
I get the above error.
I suspected the formatting was the problem.
I found in the docs how to set the postgresql date style to DMY. After doing that, I get the same error.
However, when I run the same query in Postgres cli like so:
SELECT w.machine_name, l.trasaction_time,
l.loyaltycard_number, l.recipt_no,
l.totaltrans_amount, l.amount_paid,
l.reward_points, l.redeemed_points,
cashier FROM loyalty l
JOIN warehouses w
ON l.machine_ip = w.machine_ip
WHERE l.machine_name = 'HERMSERVER'
AND redeemed_points != 0
AND trasaction_time BETWEEN '14/11/21' AND '22/02/22'
ORDER BY trasaction_time DESC;
I get the expected result. I don't know what I am doing wrong.
I want to know how I can make the database treat the date from the datepicker as dd/mm/yyyy instead of mm/dd/yyyy. I am using google cloudsql Postgres
This is the code for the handler that gets the data from the datepicker
err := r.ParseForm()
if err != nil {
app.clientError(w, http.StatusBadRequest)
}
startDate := r.PostForm.Get("startDate")
endDate := r.PostForm.Get("endDate")
outlet := r.PostForm.Get("outlet")
reportType := r.PostForm.Get("repoType")
if reportType == "0" {
rReport, err := app.models.Reports.GetRedeemedReport(startDate, endDate, outlet, reportType)
if err != nil {
app.serverError(w, err)
return
}
app.render(w, r, "tranxreport.page.tmpl", &templateData{
Reports: rReport,
})
} else if reportType == "1" {
rReport, err := app.models.Reports.GetAllReport(startDate, endDate, outlet)
if err != nil {
app.serverError(w, err)
return
}
app.render(w, r, "tranxreport.page.tmpl", &templateData{
Reports: rReport,
})
} else {
app.render(w, r, "tranxreport.page.tmpl", &templateData{})
}
As per the comments while it should be possible to change DateStyle there are a few issues with this:
The SET datestyle command changes the style for the current session. As the SQL package uses connection pooling this is of limited use.
You may be able to use "the DateStyle parameter in the postgresql.conf configuration file, or the PGDATESTYLE environment variable on the server" but this may not be available where Postgres is offered as a managed service. Note that making this change also means your software will fail if the parameter is not set (and this is easily done when moving to a new server).
A relatively simple solution is to edit your query to use TO_DATE e.g.:
BETWEEN TO_DATE($3,'DD/MM/YYYY') AND TO_DATE($4,'DD/MM/YYYY')
However while this will work it makes your database code dependent upon the format of the data sent into your API. This means that the introduction of a new date picker, for example, could break your code in a way that is easily missed (testing at the start of the month works either way).
A better solution may be to use a standard format for the date in your API (e.g. ISO 8601) and/or pass the dates to your database functions as a time.Time. However this does require care due to time zones, daylight saving etc.

Attempting to get the response from a TimeItem on my google form?

When I use getResponse(), it returns a string that doesn't even have the AM or PM value. Thus I cannot use the Date and Time functions on the response. Does someone know how to get my timeItem response to save properly.
I do know that I need to create a Date object in order to use the date and time functions. That's not the problem.
var tester = Responses[3].getResponseForItem(Items[7]).getResponse();
It returns at string like "3:00" when I would rather it return something like "3:00PM"
The TimeItem class is defined on the 24-hour clock. I don't think they explicitly provide AM and PM tags. Note, this is also the case with DateTimeItems.
Documenation: TimeItem
If you want the string to be 3:00PM/AM instead of 3:00, write a short conditional statement.
Something like:
if(timeItem > 12:00 AND timeItem < 23){
tester = tester + "PM";
} else {
tester = tester + "AM";
}

Linq to Entities does not recognize the method System.DateTime.. and cannot translate this into a store expression

I have a problem that has taken me weeks to resolve and I have not been able to.
I have a class where I have two methods. The following is supposed to take the latest date from database. That date represents the latest payment that a customer has done to "something":
public DateTime getLatestPaymentDate(int? idCustomer)
{
DateTime lastDate;
lastDate = (from fp in ge.Payments
from cst in ge.Customers
from brs in ge.Records.AsEnumerable()
where (cst.idCustomer == brs.idCustomer && brs.idHardBox == fp.idHardbox
&& cst.idCustomer == idCustomer)
select fp.datePayment).AsEnumerable().Max();
return lastDate;
}//getLatestPaymentDate
And here I have the other method, which is supposed to call the previous one to complete a Linq query and pass it to a Crystal Report:
//Linq query to retrieve all those customers'data who have not paid their safebox(es) annuity in the last year.
public List<ReportObject> GetPendingPayers()
{
List<ReportObject> defaulterCustomers;
defaulterCustomers = (from c in ge.Customer
from br in ge.Records
from p in ge.Payments
where (c.idCustomer == br.idCustomer
&& br.idHardBox == p.idHardBox)
select new ReportObject
{
CustomerId = c.idCustomer,
CustomerName = c.nameCustomer,
HardBoxDateRecord = br.idHardRecord,
PaymentDate = getLatestPaymentDate(c.idCustomer),
}).Distinct().ToList();
}//GetPendingPayers
No compile error is thrown here, but when I run the application and the second method tries to call the first one in the field PaymentDate the error mentioned in the header occurs:
Linq to Entities does not recognize the method System.DateTime.. and cannot translate this into a store expression
Please anybody with an useful input that put me off from this messy error? Any help will be appreciated !
Thanks a lot !
Have a look at these other questions :
LINQ to Entities does not recognize the method
LINQ to Entities does not recognize the method 'System.DateTime Parse(System.String)' method
Basically, you cannot use a value on the C# side and translate it into SQL. The first question offers a more thorough explanation ; the second offers a simple solution to your problem.
EDIT :
Simply put : the EF is asking the SQL server to perform the getLatestPaymentDate method, which it has no clue about. You need to execute it on the program side.
Simply perform your query first, put the results into a list and then do your Select on the in-memory list :
List<ReportObject> defaulterCustomers;
var queryResult = (from c in ge.Customer
from br in ge.Records
from p in ge.Payments
where (c.idCustomer == br.idCustomer
&& br.idHardBox == p.idHardBox)).Distinct().ToList();
defaulterCustomers = from r in queryResult
select new ReportObject
{
CustomerId = r.idCustomer,
CustomerName = r.nameCustomer,
HardBoxDateRecord = r.idHardRecord,
PaymentDate = getLatestPaymentDate(r.idCustomer),
}).Distinct().ToList();
I don't have access to your code, obviously, so try it out and tell me if it works for you!
You'll end up with an in-memory list

Zend_Validate_Date returns true on 2011-02-31

What should i do ?
$edit_end_date = '2011-02-31';
$validator_date = new Zend_Validate_Date(array('format' => 'yyyy-mm-dd'));
$isval = $validator_date->isValid($edit_end_date);
if((!$isval) || empty($edit_end_date))
{
echo "Please Enter Valid End Date. !";
}else{
echo "Entered Is Valid End Date. !";
}
how come it returns true date ?
According to the Zend API Docs, it appears that Zend_Validate_Date will only validate whether the argument passed to it, is a valid date construct (also considers locale), it will not validate if the date actually exists.
Zend_Validate_Date allows you to validate if a given value contains a date. This validator validates also localized input.
-- Edit --
Looks like you can use PHP's built in checkdate() function to determine if a date is valid or not.
There are bugs in data validation (ZF-7583 at issue tracker). Look at Zend_Validate_Date just doesn't work properly
You can use regex validation like in answer to linked question, but it will only check for syntax, not if date exists for real. For this you can use checkdate() - as Mike Purcell suggested - combined with Zend_Validate_Callback:
$validator1 = new Zend_Validate_Regex(
array('pattern' => '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/')
);
$validator1->setMessage(
"Date does not match the format 'yyyy-mm-dd'",
Zend_Validate_Regex::NOT_MATCH
);
$validator2 = new Zend_Validate_Callback(function($value)) {
// using checkdate() or other function
});