Grails Date Contraints - grails

Im trying to add constraints to a user submitted text field, which is there Date of Birth. I need the user to be at least 18 but cant be over 113 years old.
final static Date MIN_DATE = new Date(Calendar.YEAR-18)
final static Date MAX_DATE = new Date(Calendar.YEAR-100)
static constraints = {
dob(nullabe: false, min: MIN_DATE, max: MAX_DATE
}
When I,
System.out.println('Year Max Date: ' + person.MAX_DATE)
it gives me,
Year Max Date: Wed Dec 31 17:59:59 CST 1969
and so does the min date.
I tried doing
final static Date MIN_DATE = new Date().getAt(Calendar.YEAR)-18
but that didn't work at all. I also tried doing it without the -18 and got the correct answer but it was 7 hours off. When I tried to relaunch the app from local it crashed it. And I cant recreate it ever since.
I have come to the understanding that the date its giving is the "Epoch" date or the date right before Unix was launched. Im just not sure how to get around it.
Any ideas/suggestions/concerns/experience with this problem?
Any Help would be greatly appreciated.

I don't agree with these constraints, firstly as they seem arbitrary (why should someone not be older than 100? And why can't I just lie if I am 16?)
And secondly, if the webserver is up for a couple of years, these static dates will slowly drift
But anyway (these concerns aside), I believe what you want is:
final static Date MIN_DATE = Calendar.instance.with { add( YEAR, -18 ) ; it }.time
final static Date MAX_DATE = Calendar.instance.with { add( YEAR, -100 ) ; it }.time

The issue is that Date constructor expects an argument representing milliseconds since January 1, 1970, 00:00:00 GMT. Since Calendar.YEAR is a constant that is used to represent the year field from a Calendar structure and equal to 1 you are getting the above values.

You need to convert the user submitted text field (a String) to a Date object with SimpleDateFormat. Then create a Calendar with the Date object and check the Year field.
Alternatively you can just parse the text field (String) yourself and pick the year, convert to int and do the check.

Related

How to More Elegantly Calculate Epoch Time for Next Sunday at Midnight in Dart?

When a user opens my app, there's a countdown timer that shows how much time left until Sunday at midnight (which is when the week's contest would end).
To get the initial value used in the countdown, my code adds 604800000 (which is the amount of milliseconds in a week) in a loop to a starting value of 1595203200000 (which the milliseconds since epoch of an arbitrary past Sunday at midnight) until it's greater than now:
int now = DateTime.now().millisecondsSinceEpoch;
int nextSundayAtMidnight = 1595203200000; // starting value is from arbitrary past Sunday at midnight
while (now > nextSundayAtMidnight) {
print('now is still greater than nextSundayAtMidnight so adding another 604800000 until it\'s not');
nextSundayAtMidnight += 604800000;
}
print('nextSundayAtMidnight is $nextSundayAtMidnight');
It works, but it seems like there should be a better way that's based on DateTime.now without having to manually specify that arbitrary starting value. Is there?
What's the syntax in dart to do this more elegantly?
Thanks in advance!
The following code uses addition of the difference in weekdays to get the date of the upcoming Sunday and then shifts the exact DateTime to being at 11:59:59 pm. There are comments in the code that describe what each line does.
It uses the many helpful methods already provided in the DateTime class in dart.
void main()
{
var now = DateTime.now();
//Obtains a time on the date of next sunday
var nextSunday = now.add(Duration(days: DateTime.sunday - now.weekday));
//Shifts the time to being 11:59:59 pm on that sunday
var nextSundayMidnight = DateTime(nextSunday.year, nextSunday.month, nextSunday.day + 1).subtract(Duration(seconds: 1));
//Gets the difference in the time of sunday at midnight and now
var timeToSundayMidnight = nextSundayMidnight.difference(now);
print(timeToSundayMidnight);
}

Informix - Need to create date time parameters for Where clause

Informix is not my normal environment and the way it handles datetime values is throwing me for a loop. I can't imagine this is difficult, but for the life of me I'm not yet able to figure it out.
This is the SQL:
SELECT agentid,
extension As Ext,
resourcefirstname As FirstNm,
resourcelastname As LastNm,
Min(eventdatetime) As FirstIn
FROM agentstatedetail AS asdr Join
resource As r On asdr.agentid = r.resourceid
WHERE asdr.eventdatetime BETWEEN '2016-10-20 04:00:00' AND '2016-10-21 03:59:59'
AND eventtype = 3
AND assignedteamid = 14
Group By agentid, extension, resourcefirstname, resourcelastname
Order By Min(eventdatetime)
Everything works as is, but the dates in the Between clause are currently entered manually- not optimal. I just need some way to describe "yesterday at 4:00 AM" and "Today at 4:00 AM" Will somebody please clue me in?
Using Informix version 12.10.FC6DE, I can do this:
SELECT
TODAY::DATETIME YEAR TO SECOND AS today_zerohour
, TODAY::DATETIME YEAR TO SECOND - '20:00:00'::INTERVAL HOUR TO SECOND AS yesterday_dawn
, TODAY::DATETIME YEAR TO SECOND + '04:00:00'::INTERVAL HOUR TO SECOND AS today_dawn
FROM
systables
WHERE
tabid = 1;
And it returns:
today_zerohour yesterday_dawn today_dawn
2016-10-21 00:00:00 2016-10-20 04:00:00 2016-10-21 04:00:00
So, what is happening here:
The operator TODAY returns the system date as a DATE type. The DATE type does not have the precision I want (it only has year, month and day), so I cast the value (cast operator is ::) to a DATETIME with precision from year to second (the hour, minutes and seconds are set to zero):
TODAY::DATETIME YEAR TO SECOND
In Informix, for an addition or subtraction with a DATETIME value to return another DATETIME value, I need to add or subtract an INTERVAL value. So I created 2 INTERVAL values.
One INTERVAL of 20 hours to subtract from the today value (again the cast operator :: is used, this time to cast from a string to an INTERVAL):
'20:00:00'::INTERVAL HOUR TO SECOND
One INTERVAL of 4 hours to add to the today value:
'04:00:00'::INTERVAL HOUR TO SECOND

Vaadin: How to change a date format?

I am pulling a Date from a database, reassigning it as a TextField, and then toString() it, but the date comes out "Thurs 0900 OCT 12 2015" when all I need is MM/DD/YYYY format. How do I change the format?
Date myDatabaseDate = someDBGetMethod();
TextField myDateTF = new TextField()
myDateTF.setCaption("My date is: ");
myDateTF.setValue(myDatabaseDate).toString());
myDateTF.setReadOnly(true);
FormLayout fLayout = new FormLayout();
addComponent(fLayout);
fLayout.addComponent(myDateTF);
What's happening: Thu Oct 22 12:19:04 CDT 2015
What I want: 22/10/2015
Thank you in advance!
Examples make the most sense to me as I am very new to vaadin.
Vaadin Not The Problem
If trying to display a String representation of a date-time object, then Vaadin is not a part of the problem. Vaadin offers a widget, DateField, for the user to pick a date-time value. You do not need that widget for simply displaying the string representation. For display, use a TextField as you described in the Question.
So the problem is how to generate that String representation.
First be aware that Java includes two classes named "Date":
java.util.Date
java.sql.Date
Confusingly, they are not parallel. The util one is a date plus a time-of-day in UTC. The sql one is meant to represent a date-only, but is poorly designed; as a hack it subclasses the util one but alters the time-of-day to be 00:00:00.000. These old date-time classes in early Java are a bad mess.
From a database you should be receiving the latter, java.sql.Date for a date-only stored value. If you were storing date-time values, then you should be getting java.sql.Timestamp objects from your JDBC driver.
java.time LocalDate
As java.sql.Date is one of the old clunky date-time classes bundled with early Java, we should convert to the new classes found in the java.time framework built into Java 8 and later. See Tutorial.
For a date-only value, java.time offers the LocalDate class. The "Local" in the name refers to any locality rather than a particular locality. It represents the vague idea of a date, but is not tied to the timeline. A date starts earlier in Paris than in Montréal, for example. If you care about exact moments on the timeline, you would be using java.sql.Timestamp rather than java.sql.Date.
Converting from java.sql.Date to java.time.LocalDate is an easy one-liner, as a conversion method is provided for you.
LocalDate localDate = myJavaSqlDate.toLocalDate();
Going the other way is just as easy, when storing data into the database.
java.sql.Date myJavaSqlDate = java.sql.Date.valueOf( localDate );
With a LocalDate in hand, you can call on the java.time.format package to format a string localized for easy reading by the user. Specify the Locale expected by the user.
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH );
String output = localDate.format( formatter );
Example output:
dimanche 1 novembre 2015
ZonedDateTime
Let’s consider if you did get a java.sql.Timestamp rather than java.sql.Date.
We can convert from a java.sql.Timestamp to a Instant, a moment on the timeline in UTC.
Instant instant = myTimestamp.toInstant();
Next, assign a time zone.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId);
We use the java.time.format package to create the String representation. Note the chained calls, the second one setting a specific Locale. If not specified, your JVM’s current default Locale is implicitly applied. Better to be explicit.
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.FULL ).withLocale ( Locale.CANADA_FRENCH );
String output = zdt.format ( formatter );
Example output:
dimanche 1 novembre 2015 2 h 24 EST
java.util.date object does not contain any information how to present himself as String. That's because in different locations communities writes dates in different ways. So Java separates operations on dates from printing them out on the screen.
What you are missing in your code is a DateFormat.
Date myDatabaseDate = new Date(2014,10,10);
DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT, Locale.UK);
TextField myDateTF = new TextField();
myDateTF.setCaption("My date is: ");
myDateTF.setValue(format.format(myDatabaseDate));
myDateTF.setReadOnly(true);
layout.addComponent(myDateTF);
I would strongly encourage you however to use Java 8 Dates API since Java 7 Dates API is a total mess. You can read more about that here What's wrong with Java Date & Time API?

Timezone Offset in Angular JS and Rails

Background: I'm building an app with Angular JS as web interface and Rails API. The problem I am having is passing a date from Angular to Rails.
Issue: I have a form with a Date of Birth date field, when a user inputs his DOB say March 1st, 1985, Angular interprets it as 1985-03-01 00:00 +0800 (if you're in Hong Kong or Singapore) and sends a request to Rails. The first thing Rails does with it is to convert it to UTC, which means the datetime is now 1985-02-28 16:00 UTC. Therefore, when the date is saved to the database date column, it becomes Feb 28, 1985.
Solution for now: What I'm doing now is on Angular side, I get the Timezone offset hours and add it to the date, so instead of 1985-03-01 00:00 +0800, it is now 1985-03-01 08:00 +0800. When Rails get it, it converts to 1985-03-01 00:00 UTC and so saves the correct date to db. However, I believe this is a better alternative to tackle this issue.
Thinking about parsing just the date in Rails, yet the params[:dob] I see is already UTC by the time I get it. Would love to know if there is a better practice than my current solution. Thank you for any comment and feedback.
This problem is actually quite common, and stems from two separate but related issues:
The JavaScript Date object is misnamed. It's really a date + time object.
The JavaScript Date object always takes on the characteristics of the time zone for the environment in which it is running in.
For a date-only value like date-of-birth, the best solution to this problem is to not send a full timestamp to your server. Send just the date portion instead.
First, add 12 hours to the time, to use noon instead of midnight. This is to avoid issues with daylight saving time in time zones like Brazil, where the transition occurs right at midnight. (Otherwise, you may run into edge cases where the DOB comes out a day early.)
Then output the date portion of the value, as a string in ISO format (YYYY-MM-DD).
Example:
var dt = // whatever Date object you get from the control
dt.setHours(dt.getHours() + 12); // adjust to noon
var pad = function(n) { return (n < 10 ? '0' : '') + n; }
var dob = dt.getFullYear() + '-' + pad(dt.getMonth()+1) + '-' + pad(dt.getDate());
Another common way to do this is:
var dt = // whatever Date object you get from the control
dt.setHours(dt.getHours() + 12); // adjust to noon
dt.setMinutes(dt.getMinutes() - dt.getTimezoneOffset()); // adjust for the time zone
var dob = dt.toISOString().substring(0,10); // just get the date portion
On the Rails side of things, use a Date object instead of a DateTime. Unlike JavaScript, the Rails Date object is a date-only object - which is perfect for a date-of-birth.

Parsing to a total DateTime object in Rails

I'm currently given three values in a table
A date value in the format of %dd-%mname-%yy (i.e 06-may-05), and am parsing that using Date.parse(input,true) to fix the issue with the leading values.
I'm then given a time value in the form of %hh:%mm:%ss.%ms (the ms of which I can take or leave) and a third value of a GMT offset.
I can't really see anyway to convert these three values into a single DateTime object that would allow me to manipulate it using the range of ruby tools without first parsing the second value to time, somehow changing the offset ((given as a + or - n value) as in +2 or -6)to a signed int and then applying it and then parsing this all to a super dateTime object.
There's got to be a better way. Is there?
Chronic may be able to parse this (if you concatenate everything in one string, maybe with some modifications) but I haven't checked.
Okay in order to create a dateTime value with the time and the date given and to take into account an offset you need the following code
d = DateTime.parse(dateVal+" "+TimeVal)
offset = Rational(offset_val,24)
d = d.new_offset(offset)
So take your date, given to you as say 05 May 2010 and a timeval in the form hh:mm:ss
With an offset of +- any value, for this instance say -8
Then this code will generate you a new date object, offset to the amount you require

Resources