I'm using a HSQLDB to make a small program (with JavaFX gui) and I'm currently trying to get the "reservation" part to work (the user can add new ones or search for existing ones in a restricted period of time).
For that I already added a few dates beforehand (I'm using a database.sql script), e.g.:
INSERT INTO reservations(begin, end) VALUES ('2013-08-01', '2013-08-31')
I already wrote a few methods (create, update, delete, search, findAll) and now I'm kind of stuck on the "create" part.
I want to insert new reservations into the DB with
pstmt = con.prepareStatement("INSERT INTO reservations(begin, end) VALUES (?,?)");
but I'm having problems creating new Dates that I can insert.
pstmt.setDate(1, (java.sql.Date) beg);
Doesn't work (I'm using java.util.Date objects to save the exported dates from the DB), it just aborts my tests (jUnit).
Calendar cal1 = Calendar.getInstance();
cal1.set(2014, 0, 1);
Date beginn = cal1.getTime();
only creates dates in the form of: Wed Jan 01 12:23:15 CET 2014
But (and I don't know how exactly dates are saved in HSQLDB) I want the date to be "YYYY-MM-DD".
So, what's the best way of converting the calendar dates into the format I need (and caste them? Unfortunately, casting a String to Date doesn't work). And: Is my approach of using java.util.Date dates okay if I'm going to use JavaFX to let the user select a starting and an end date?
Instead of (java.sql.Date) beg causing a ClassCastException you should write:
new java.sql.Date(beg.getTime()); // provided beg is of type java.util.Date as you wrote
If you use strings in VALUES-clause you might consider JDBC-escape-syntax for dates. And your statement "only creates dates in the form of: Wed Jan 01 12:23:15 CET 2014" does not matter at all because you only see the output of method toString()of java.util.Date. It is not relevant for the internal state or storage in db. Your wish "I want the date to be "YYYY-MM-DD"." is rather relevant for representation layer of your application, not for the internal storage format of db which you have no control about other than choosing the appropriate db column type (here: ANSI-SQL-DATE).
In the representation layer you can use classes like SimpleDateFormatwith pattern "yyyy-MM-dd" for the output you wish.
EDIT (because of questions in comments):
Okay, you really don't need to worry about the toString()-representation of a java.util.Date-timestamp. Its internal state is only a long representing the elapsed millis since 1970-01-01 not counting leap seconds. Just ignore the standard output of java.util.Date which rather displays the system zone context but not so much the internal state. Using a.before(b) is quite okay and has nothing to do with the weird output of toString()-method of java.util.Date.
Furthermore: You have no real control about how your database tool displays the date column values. That is the secret of the tool you use. The internal state inside db might be quite different so every db is like a kind of black box.
But when you read the date values from db and present the data to the user then and exactly then you have to worry about the representation of the java.util.Date-objects. For this purpose I have recommended to use SimpleDateFormat - see above. But this adaptation (conversion to readable human date format) is not in db-tool, not in the JDBC-layer, but only in user-representation layer, normally in UI.
Related
My application requires the following.
In my application(in struts), we need to support Persian Calendar.
When we submit a form, date is coming as String in Action class. We need to save this date in Persian format in DB. We have configured DB for Persian Calendar. And while retrieving data from DB user should be able to see the date in Persian format only.
Also, the user can switch in 2 languages(English, Persian). So, application should support both type of calendars(Gregorian and Persian). If user logged-in in English, Gregorian calendar should be visible. If user logged-in in Persian language, then Persian Calendar should be visible.
For date conversion from Gregorian to Persian I am using below:
http://www.dailyfreecode.com/forum/converter-gregorian-date-jalali-date-20288.aspx
In above requirement, I am facing 2 issues:
While submitting a form, how can we save date(which is in String format in Action class) in Persian format in DB?
While retrieving data from DB, it should come in Persian format. As of now, the JDBC client is retrieving the date in Gregorian Calender.
I am passing java.sql.Date(today's date) which is getting saved in persian format in DB. Using below code.
java.sql.Date sqlDate = null;
java.util.Date utilDate = new Date();
sqlDate = new java.sql.Date(utilDate.getTime());
PreparedStatement psmtInsert = conn.prepareStatement(insertQuery);
psmtInsert.setDate(1, sqlDate));
psmtInsert.executeUpdate();
For retrieving:
PreparedStatement psmtSelect = conn.prepareStatement("select dateOfJoining from EMPLOYEE");
ResultSet resultSet = psmtSelect.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getDate(1));
}
But it is returning date in Gregorian type.
Do we have any setting in Tomcat/JVM/JDBC client which converts date returned from DB into Persian Format itself(Like we have NLS_CALENDAR ,NLS_DATE_FORMAT in Oracle)?
For 1st issue, if I am passing date in Persian format then In DB it is saving incorrectly. PFB my code:
java.sql.Date sqlDate = null;
java.util.Date utilDate = new Date("1397/02/04");
sqlDate = new java.sql.Date(utilDate.getTime());
PreparedStatement psmtInsert = conn.prepareStatement(insertQuery);
psmtInsert.setDate(1, sqlDate));
psmtInsert.executeUpdate();
Above is inserting as 0777/09/13 in DB.
How can we overcome the above issues?
Thanks in advance.
There is no calendar type in java.sql.Date so it is impossible to force it to Persian. All date/time values in JDBC are normalized in a neutral form and Oracle Database uses a neutral form as well for storage and processing. When NLS_CALENDAR is PERSIAN, Oracle converts the value to and from the neutral form and it is just "presenting" it in the Persian calendar convention while it is handling in the neutral form internally.
Usually it is optimal to use a neutral form consistently for all values in the backend. Typically a converter is used in the UI layer as part of the localization to tailor to the preferred locale for individual users. If localization in Java in the middle tier is needed, the java.time.chrono package that Douglas is suggesting above would be a clean solution.
While submitting a form, how can we save date(which is in String format in Action class) in Persian format in DB?
Store the date as a DATE data type and when you want to insert it into the table use TO_DATE with the NLS calendar parameter for Persian to convert it from a Persion formatted string to a date:
SQL Fiddle
Query 1:
SELECT TO_DATE(
'1397/02/05',
'yyyy/mm/dd',
'nls_calendar=persian'
)
FROM DUAL
Results:
| TO_DATE('1397/02/05','YYYY/MM/DD','NLS_CALENDAR=PERSIAN') |
|-----------------------------------------------------------|
| 2018-04-25T00:00:00Z |
While retrieving data from DB, it should come in Persian format. As of now, the JDBC client is retrieving the date in Gregorian Calender.
When you output the value, just specify the calendar you want to use to format it. So for Persian, use TO_CHAR with the NLS calendar parameter for Persian:
Query 2:
SELECT TO_CHAR(
DATE '2018-04-25',
'yyyy/mm/dd',
'nls_calendar=persian'
)
FROM DUAL
Results:
| TO_CHAR(DATE'2018-04-25','YYYY/MM/DD','NLS_CALENDAR=PERSIAN') |
|---------------------------------------------------------------|
| 1397/02/05 |
Do we have any way using which JDBC client retrieve date in Persian format.
This is a common misconception. A DATE data type stored in Oracle tables as 7 bytes containing year (2 bytes), month, day, hours, minutes and seconds (1 byte each). It does not have any "format" (but it is effectively stored in the Gregorian calendar).
JDBC does not transfer a formatted date, it just transfers those 7 bytes and stores it in a java.sql.Date class (which also just stores those bytes).
If you want to format a DATE data type then you need to convert it to another data type; typically a string for which you want to use TO_CHAR in the Oracle database (or some other method to format Dates in Java).
Just to provide the inputs for those who still are looking how to implement the Persian calendar in the application.
My application should support Gregorian and Persian calendar, also Oracle and PostgreSQL DBs should be supported.
To implement the Persian calendar with minimum efforts performed the below steps:
Converting every date coming from UI into Gregorian format in validate() of form using the implementation suggested in below link
http://www.dailyfreecode.com/forum/converter-gregorian-date-jalali-date-20288.aspx
Once the dates are converted to Gregorian the whole application will keep running as it was running earlier with Gregorian dates.
While saving the date in DB, I decided to store the date in Gregorian format only as I need to support PostgreSQL DB as well and it was not supporting the Persian Calendar.
While fetching the data to UI, the date will be retrieved from DB and again I am converting the date in Persian format.
To show the Persian calendar on UI, refer the below link. It has other calendars implementation as well
http://keith-wood.name/calendars.html
The above approach can help implementing most of the different calendars.
java.sql.Date is defined to be in UTC which is Gregorian. Getting a DATE from the database as a java.sql.Date is not likely to do anything useful. The right answer would be to define a PersianChronology which extends java.time.chrono.AbstractChronology and PersianLocalDate which implements java.time.chrono.ChronoLocalDate. Then get the value from the database as a PersianLocalDate. That's a lot of work but it is in theory the right thing to do.
PersianLocalDate per = rs.getObject(col, PersianLocalDate.class);
I think this could be made to work. Not easy but possible. If your PersianLocalDate class defines the following method
public static PersianLocalDate of(oracle.sql.DATE date) { ... }
then Oracle Database JDBC would use that method to construct a PersianLocalDate in the getObject call above. The fun part would be implementating the of(DATE) method. All of the oracle.sql.DATE methods assume a Gregorian calendar. Your best bet is to call DATE.getBytes and interpret the bytes yourself. Bytes 0 and 1 are the year, 2 is the month and 3 is the day of the month. TIMESTAMP.getJavaYear will convert those two bytes into an int year. It doesn't know anything about calendars; it's just doing arithmetic. Depending on what the database does in sending a Persian DATE as a query result that should let you construct a PersianLocalDate. If the database is converting to Gregorian, you'll have to convert back to Persian. Your PersianChronology should help with that.
Going the other way, sending a PersianLocalDate to the database is going to be more interesting. The Oracle Database JDBC drivers have no capability of converting an unknown class to a database type like DATE, nothing equivalent to the of method hook described above. You could try making PersianLocalDate extend oracle.sql.ORAData. The toDatum method would have to return an oracle.sql.DATE with the same bytes that the database sent as a query result.
A simpler approach, maybe, would be to send Persian dates back and forth to the database as VARCHARs/Strings. The drivers would call a static of(String) method on PersianLocalDate so getting a PersianLocalDate would be easy. If the database does the right thing with PersianLocalDate.toString results then calling setString makes sending the values easy. If not then define PersianLocalDate.toDatabaseString and do the conversion yourself.
This is a use case that we talked about when we implemented support for java.time but we simply did not have the resources required to do anything. And we didn't know how common it would be so it was hard to justify doing the work. If you have a support contract I'd encourage you to file an SR and ask for an enhancement request. If you can provide a PersianChronology and PersianLocalDate it would be easier for me to get some resources allocated to do something. Maybe nothing more than a hook to make setObject work, but at least that. I wish I could be more help.
I have been reading different articles on the said question yet i am unable to figure out what should be the best strategy to store the date in db.
I will be receiving the ISO8601 date via path-param in a rest call. What I have decided
Use Joda-Time to parse the date.
Extract UTC-0 time out of the date and the hours offset
Store UTC-0 in DateTime datatype in mysql db and store offset in varchar(5).
When I have to search something based on the date (an exposed rest api). I will use the search criteria (input date) extract the UTC-0 time and hours offset and compare the two columns in the db i.e. where table.dateInUTC0 = :inputDateInUTC0 AND table.hoursOffset = :inputHoursOffset
I am not sure about step 4. Am i doing i right ?
I am not sure about step 4. Am i doing i right ?
Really, it depends on what you are trying to do.
If you want the search to only match if the searcher is using the same timezone as the original data, then you are doing it right.
If you don't want that, you are doing it wrong.
Ask yourself this: If you enter the same date / time in your local time zone and UTC (or some other time zone), do they mean the same thing for clients of your server? Should they?
In my Java app I must save data to Oracle 11g with object created date and time and for this I convert java.util.Date() to java.sql.Date() in format as new java.sql.Date(new java.util.Date().getTime()). But I noticed, that after the data inserted, oracle truncate the time part of date and I get something like 16/09/2015. but I need format like this: 16/09/2015 9:55:44. the second format created by oracle's sysdate() procedure. How I can get the second format from java code?
From memory (it's been a while), java.sql.Date is used to hold dates (no time) only, if you want time information as well, you need to use java.sql.TimeStamp instead.
Do not use java.sql.Date if you want to store date and time. Just use java.util.Date without any conversion. Simple and easy. There is no need for java.sql.TimeStamp either.
And make sure your NLS settings (e.g. in SQL Developer) are such that they display both date and time as Oracle does not distinguish between dates with and without time.
I guess Oracle does not truncate. For example, if you use Oracle SQL Developer, you have to update NLS parameter "Date Format" to see a time.
By default it just equal "DD-MON-RR"
This question has few sub-questions!
What is best data type for storing date?
java-s Date, or just long - in miliseconds, formated String?
Client/Server time-zone problem
a) How to show date on client side (correct time zone)
b) If client inserts date, server needs to insert date in servers timezone or better fixed app timezone? (correct api?)
Sorting is easy with long data type, but is it working with Date?
Manipulating (for example select records for last 4 days, or between two dates, etc...).
Is there any good manual for this topic!
Currently, I am using long for date data type, but it somehow does't feel right (for example browsing in admin console is confusing).
Thanks!
java.util.Date is a supported type
How you show this to the user is a more generic java problem. All dates are stored in UTC. I suggest you take a look at joda-time for handling timezones and dates.
Yes, sorting of Date objects is supported in queries etc.
Filtering is also supported, eg, date > yesterday && date < today. Don't forget to bear in mind there are limitations when you impose filters. For example, those inequality filters can only apply to one property at a time. See restrictions on queries
For example, when I extract from a database a Date() variable, it contains a date with "+04:00" shift.
According to my locale's settings.
So, UTC time is "ourTime" MINUS 4 hours.
Then, a user tells where he/she is from. Now, we need to save his/her shift.
LET'S SAY it is -01:00.
And finally, this user tells us where's he/she is heading, let's say this place has a time shift of +05:00.
How do we save this town's or place's time shifts in the DB so that according to where he/she's from
we could calculate the time difference with our current locale?
Also, date save light things, how do we work with them?
You don't.
As long as you're using java.util.Date objects (or java.sql.Date, or java.sql.Timestamp) the database will contain UTC time, that's what java.util.Date holds internally.
You need to format and/or parse these dates according to local timezone. Take a look at SimpleDateFormat for more information. Of course, if you have dates in the database that you manually parsed, then you may be SOL.