Im converting date time string format to Timestamp (java.sql) from different format. I have converted it to LocalDateTime based on different format. Is there anyway to convert LocalDateTime object to Timestamp?
It’s more delicate than you think, so good you asked.
Since you can use java.time, the modern Java date and time API, you should not wish to apply the old-fashioned and poorly designed Timestamp class too.
I am assuming that you were asking for a Timestamp because you need something that you can store into an SQL database column of type timestamp (without time zone). Allow me to mention that for most purposes you don’t want such a column. The standard SQL datatype timestamp doesn’t live up its name. While the idea of a timestamp is that it should identify an unambiguous point in time when something happened, an SQL timestamp does not define such a point in time. It defines a date and time of day, and anyone is free to interpret it in any time zone, allowing for a variation of some 26 hours. Instead for a point in time you should use timestamp with timezone. It doesn’t live up to its name either in that it doesn’t let you choose the time zone. It stores times in UTC, so does identify a unique point in time.
On the Java side use an OffsetDateTime for storing into a timestamp with timezone column. Since you’ve got a LocalDateTime, you need to convert. And for the conversion you need to know the time zone intended behind your LocalDateTime. For example:
final ZoneId zone = ZoneId.of("Asia/Tehran");
LocalDateTime ldt = LocalDateTime.of(2019, 2, 25, 23, 45);
OffsetDateTime odt = ldt.atZone(zone).toOffsetDateTime();
System.out.println("As OffsetDateTime: " + odt);
As OffsetDateTime: 2019-02-25T23:45+03:30
Store into your database:
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(your_ts_with_timezone) values (?)");
ps.setObject(1, odt);
ps.executeUpdate();
If either for some reason you do need a timestamp without time zone in your database or you cannot change it, you don’t need any conversion at all. Just store the LocalDateTime you had:
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(your_ts_without_timezone) values (?)");
ps.setObject(1, ldt);
If you are programming to a legacy API that requires an old-fashioned java.sql.Timestampobject, things are getting even delicater. A Timestamp does define a point in time. So you will now need to convert from a LocalDateTime that does not define a point in time, to a Timestamp that does define one, then pass the Timestamp to an API that may store it in a database column that again does not define an unambiguous point in time. You will need to be sure which time zones are used for the conversions, and still there may be corner cases that fail or (worse) give incorrect results. However, as the_storyteller mentioned in a comment, the conversion is straightforward enough:
Timestamp ts = Timestamp.valueOf(ldt);
System.out.println("As old-fashioned Timestamp: " + ts);
As old-fashioned Timestamp: 2019-02-25 23:45:00.0
The conversion uses your JVMs default time zone. This setting is also used by TImestamp.toString(), so the output is as expected. This is shaky, though, since any program running in the JVM may change the default time zone setting at any time, so generally you don’t know what you get. To exercise control over the time zone used for conversion:
Instant i = ldt.atZone(zone).toInstant();
Timestamp ts = Timestamp.from(i);
Links
SQL- Difference between TIMESTAMP, DATE AND TIMESTAMP WITH TIMEZONE?
try it out with java 8 built in classes
public class Test {
public static void main(String[] args) {
Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now());
// java timestamp class
System.out.println(timestamp);
// miliseconds
System.out.println(timestamp.getTime());
}
}
Related
I have a Timestamp object and a TimeZone object
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
TimeZone userTimeZone = preferenceService.getPreferredTimezone();
I want a function which modifies timestamp as per the userTimeZone . The function should return Timestamp. Could someone help ?
Your question is non-sensical. A Timestamp instance represent an instant in time. It doesn't have timezone info and isn't a timezoned stamp.
Instead, when showing a Timestamp to a user, in the step of 'convert this computer-time-kept concept to something to show the user', you'd do the job there. You wouldn't do that by first 'converting the timestamp to this timezone', you'd either do that in one go, or better yet, get to the java.time package as fast as possible because all other time libraries (including those in almost all DB engines) are non-sensical.
In java.time terms, you'd get to a ZonedDateTime, and hten you can convert that to another zone, and from there, potentially via a LocalDateTime, to rendering it to the user.
Given that you said the function must return a Timestamp, the code that uses this method is broken, so fix it there.
An external API returns an object with a date.
According to their API specification, all dates are always reported in GMT.
However, the generated client classes (which I can't edit) doesn't set the timezone correctly. Instead, it uses the local timezone without converting the date to that timezone.
So, long story short, I have an object with a date that I know to be GMT but it says CET. How can I adjust for this mistake withouth changing my local timezone on the computer or doing something like this:
LocalDateTime.ofInstant(someObject.getDate().toInstant().plus(1, ChronoUnit.HOURS),
ZoneId.of("CET"));
Thank you.
tl;dr ⇒ use ZonedDateTime for conversion
public static void main(String[] args) {
// use your date here, this is just "now"
Date date = new Date();
// parse it to an object that is aware of the (currently wrong) time zone
ZonedDateTime wrongZoneZdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("CET"));
// print it to see the result
System.out.println(wrongZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// extract the information that should stay (only date and time, NOT zone or offset)
LocalDateTime ldt = wrongZoneZdt.toLocalDateTime();
// print it, too
System.out.println(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// then take the object without zone information and simply add a zone
ZonedDateTime correctZoneZdt = ldt.atZone(ZoneId.of("GMT"));
// print the result
System.out.println(correctZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
Output:
2020-01-24T09:21:37.167+01:00[CET]
2020-01-24T09:21:37.167
2020-01-24T09:21:37.167Z[GMT]
Explanation:
The reason why your approach did not just correct the zone but also adjusted the time accordingly (which is good when desired) is your use of a LocalDateTime created from an Instant. An Instant represents a moment in time which could have different representations in different zones but it stays the same moment. If you create a LocalDateTime from it and put another zone, the date and time are getting converted to the target zone's. This is not just replacing the zone while keeping the date and time as they are.
If you use a LocalDateTime from a ZonedDateTime, you extract the date and time representation ignoring the zone, which enables you to add a different zone afterwards and keep the date and time as it was.
Edit: If the code is running in the same JVM as the faulty code, you can use ZoneId.systemDefault() to get the same time zone as the faulty code is using. And depending on taste you may use ZoneOffset.UTC instead of ZoneId.of("GMT").
I am afraid you will not get around some calculations here. I'd strongly suggest to follow an approach based on java.time classes, but alternatively you might use the java.util.Calendar class and myCalendar.get(Calendar.ZONE_OFFSET) for those calculations:
https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#ZONE_OFFSET
What is the best way to write the following code snippet in Java 8?
private Timestamp resetTime(Timestamp ts) {
ts.setHours(0);
ts.setMinutes(0);
ts.setSeconds(0);
return ts;
}
I was going to use the Calendar class but then read that it is advisable not to do so in Java 8. Any help would be greatly appreciated. Thanks.
Your code seems to try to adjust the Timestamp object to the start of the day in the default time zone (it doesn’t in all cases do that to perfection).
In the old days we used Timestamp to transfer a value to an SQL timestamp with or without time zone. The latter is somewhat self-contradictory: a time stamp is supposed to define a point in time, but a date and time of day without time zone or UTC offset doesn’t do that. So let’s first assume that you want a value to transfer to an SQL database that needs a timestamp with time zone. The type to use for that in Java 8 (assuming JDBC 4.2 or later driver) is OffsetDateTime (some JDBC drivers also accept Instant). Since the databases I know of always use UTC as time zone, I find it most natural and least confusing to transfer an OffsetDateTime in UTC.
private OffsetDateTime resetTime(LocalDate date) {
return date.atStartOfDay(ZoneId.systemDefault())
.toOffsetDateTime()
.withOffsetSameInstant(ZoneOffset.UTC);
}
Example use:
OffsetDateTime ts = resetTime(LocalDate.of(2019, Month.NOVEMBER, 30));
System.out.println(ts);
Output when running in the Africa/Blantyre time zone (just to pick a time zone at random):
2019-11-29T22:00Z
My method accepts a LocalDate argument. A LocalDate is a date without time of day and all that the method needs since it is setting the time of day to 00:00:00 anyway.
Should your database require a timestamp without time zone (not recommended), you will need a LocalDateTime instead:
private LocalDateTime resetTime(LocalDate date) {
return date.atStartOfDay();
}
I was going to use the Calendar class but then read that it is
advisable not to do so in Java 8.
Your are completely correct. Before the advent of java.time in 2014 the Timestamp class was used with SQL databases and the Calendar class would have been the correct means for you task (with the Joda-Time library as a probably better alternative). Even though both Timestamp and Calendar were poorly designed. Now they are long outdated, we should not use any of them anymore.
Link: Oracle tutorial: Date Time explaining how to use java.time.
You can user java.time.ZonedDateTime and java.sql.Timestamp together
Timestamp.valueOf(ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS).toLocalDateTime());
I use this code to change util to sql, but the record happens with seconds and another value after
String insertAttendence = null;
insertAttendence = "INSERT INTO ATTENDANCE (PRSN_ID,DATE,ARRIVAL,DEPART,DATE_ARRIVAL_FROM,DATE_DEPARTURE_TO) VALUES (?,?,?,?,?,?)";
PreparedStatement psAttendence = null;
psAttendence = dbConnection.prepareStatement(insertAttendence);
psAttendence.setInt(1, personIdForGraphics.intValue());
java.sql.Date sqlDate = new java.sql.Date(dates.get(i).getTime());
psAttendence.setDate(2, sqlDate);
In the database it is saved as follows 2019-07-26 11: 53: 18.0, I want it to be saved so 2019-07-26 11:53:18, how to change it?
You don’t want to
You don’t want the datetime in your database to have a specific format. Good practice in all but the simplest throw-away programs is to keep your user interface apart from your data model. The value of the datetime belongs in your model, so keep your datetime there and never let the user see it directly. When you adhere to this, it will never matter which format the datetime has got in the database. Whenever the user should see the date, format it into a String and show the string to the user. Similarly if you need a specific format for exchange with another system, format the datetime into a string for that purpose. If the user needs to enter a date and/or time, either accept a string or use a date picker or time picker.
You cannot
As #GuidoG has already said in comments, a datetime is stored in the database in some internal format that we don’t know and shouldn’t care about. It certainly isn’t the 2019-07-26 11: 53: 18.0 that you reported. You may have seen that in some query tool or as a result of retrieving the datetime as a string from your database, I don’t know. It may also be that you can configure your query tool to show you a different format. You can think of the datetime in the database as a date and time of day, nothing more, nothing less.
In short “format” applies only to the string representations of datetimes, not to the datetimes themselves.
java.time and JDBC 4.2
The java.sql.Date class that you were using is poorly designed and long outdated. Also your JDBC driver should treat it as a date without time of day, and most JDBC drivers do (so it’s a bit weird how you got your code to store 2019-07-26 11: 53: 18.0 with non-zero time of day).
Assuming that you want to store a point in time (a timestamp), change your database column to datatype timestamp with time zone and then store an OffsetDateTime into it. I am assuming that dates.get(i).getTime() gives you the milliseconds since the epoch.
OffsetDateTime dateTimeToSave = Instant.ofEpochMilli(dates.get(i).getTime())
.atOffset(ZoneOffset.UTC);
psAttendence.setObject(2, dateTimeToSave);
If you cannot change the datatype, you may store a LocalDateTime into your database column using psAttendence.setObject in the same way, but you will have to make sure yourself that you get a LocalDateTime in the right time zone since the object itself carries neither time zone nor offset. UTC is recommended.
Tutorial link: Oracle tutorial: Date Time explaining how to use java.time.
import java.util.Date;
import java.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-DD hh:mm");
String strDate= formatter.format(date);
System.out.println(strDate);
}
}
I have a java.util.Date object, and I need to insert it into a datetime field in MySQL in UTC format.
java.util.Date date = myDateFromSomewhereElse;
PreparedStatement prep = con.prepareStatement(
"INSERT INTO table (t1, t2) VALUES (?,?)");
java.sql.Timestamp t = new Timestamp(date.getTime());
prep.setTimestamp(1, t, Calendar.getInstance(TimeZone.getTimeZone("PST"));
prep.setTimestamp(2, t, Calendar.getInstance(TimeZone.getTimeZone("UTC"));
System.out.println(prep.toString());
Which gives me the prepared SQL statement string:
INSERT INTO table (t1, t2) VALUES ('2012-05-09 11:37:08','2012-05-09 11:37:08');
The timestamp returned is the same timestamp regardless of the timezone I specify. It's ignoring the Calendar object with timezone that I specify. What is going on and what am I doing wrong?
Jordan, actually you had the right idea. The problem is there's a bug in MySQL JDBC driver and the Calendar argument is completely ignored by default. Look at the source code for PreparedStatement to really see what's going on.
Notice it format's the Timestamp using the JVM's time zone. This will only work if your JVM is using UTC time zone. The Calendar object is completely ignored.
this.tsdf = new SimpleDateFormat("''yyyy-MM-dd HH:mm:ss''", Locale.US);
timestampString = this.tsdf.format(x);
In order for MySQL to use the Calendar argument, you have to disable the legacy date/time code with the following connection option:
useLegacyDatetimeCode=false
So you might use it when connecting to the database like this:
String url = "jdbc:mysql://localhost/tz?useLegacyDatetimeCode=false"
If you disable the legacy datetime code using the above line, then it WILL render your Timestamp in the target Calendar's time zone:
if (targetCalendar != null) {
targetCalendar.setTime(x);
this.tsdf.setTimeZone(targetCalendar.getTimeZone());
timestampString = this.tsdf.format(x);
} else {
this.tsdf.setTimeZone(this.connection.getServerTimezoneTZ());
timestampString = this.tsdf.format(x);
}
It's pretty easy to see what's going on here. If you pass in a Calendar object, it will use this when formatting the data. Otherwise, it will use the database's time zone to format the data. Strangely, if you pass in a Calendar, it will also set the time to the given Timestamp value (which seems to be pointless).
Check this link for explanation for MySQL (and you shouldn't try to apply advices about Oracle to MySQL).
The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC.
MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.) By default, the current time zone for each connection is the server's time.
TimeZones are just different ways to view a date (which is a fixed point in time). I wrote a little example here (pay close attention to the assert):
// timezone independent date (usually interpreted by the timezone of
// the default locale of the user machine)
Date now = new Date();
// now lets get explicit with how we wish to interpret the date
Calendar london = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"));
Calendar paris = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris"));
// now set the same date on two different calendar instance
london.setTime(now);
paris.setTime(now);
// the time is the same
assert london.getTimeInMillis() == paris.getTimeInMillis();
// London is interpreted one hour earlier than Paris (as of post date of 9th May 2012)
String londonTime = london.get(Calendar.HOUR) + ":" + london.get(Calendar.MINUTE);
String londonTZ = london.getTimeZone().getDisplayName(london.getTimeZone().inDaylightTime(london.getTime()), TimeZone.SHORT);
System.out.println(londonTime + " " + londonTZ);
// Paris is interpreted one hour later than Paris (as of post date of 9th May 2012)
String parisTime = paris.get(Calendar.HOUR) + ":" + paris.get(Calendar.MINUTE);
String parisTZ = paris.getTimeZone().getDisplayName(paris.getTimeZone().inDaylightTime(paris.getTime()), TimeZone.SHORT);
System.out.println(parisTime + " " + parisTZ);
The output to this snippet is (the result will be different depending on execution date/time):
8:18 BST
9:18 CEST
Your snippet in the question is simply not doing anything with regard to the date being stored. Usually databases are configured for a native TimeZone. I advise storing an extra field representing the TimeZone to be used when interpreting the date.
It is not (generally) a good idea to modify dates (which are essentially just milliseconds before/after a fixed point in time) as this would be a lossy modification that would be interpreted differently at different points in the year (due to daylight savings time).
Or this : http://puretech.paawak.com/2010/11/02/how-to-handle-oracle-timestamp-with-timezone-from-java/