spring boot convert datetime with timezone to '0' timezone in server - java

I want to store all date time and when a user wants to get information. The server must to return data with datetime and 3rd party devices (like Android , IOS, Web apps) should convert that datetime for specific timezone. The basic goal is store all date timezone with "0" timezone

You can use Java8 ZonedDateTime to get time in UTC. My assumption is 0 timezone means UTC
ZonedDateTime.now(ZoneOffset.UTC);// This will give current time in UTC
To convert ZontedDateTime , You can put GMT,US/Central etc in the config file
public static ZonedDateTime getDateinTimeZone(String timeZone,String dateInSting )
{
return ZonedDateTime.parse(dateInSting).now(ZoneId.of(timeZone));
}

Related

Spring Data MongoDB - when saving LocaDate/LocalDateTime the value is being set to yesterday

I've got a problem with saving Java8 Date API values to MongoDB database. Whenever a new LocalDate instance (LocalDate.now()) is being saved, as a result we are getting value with yesterdays date with time set to 23:00 PM.
Example:
dt.getDate().toString()
is giving me "2017-03-17"
but when i look into the database i have a value like this:
"dt" : ISODate("2017-03-16T23:00:00.000Z")
My time zone is UTC+01:00
MongoDB saves the date in UTC time.
LocalTime is your wall clock time.
When you pass it to MongoDb, spring will convert the LocalTime to Instant(UTC time) by using your System Zone.
Consider
LocalDateTime localDateTime = LocalDateTime.parse("2017-03-17T00:00:00")
Something like this happpens
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
This is where your local time is changed to UTC instant by applying offset (+01:00) from your local time.
Output(in UTC) : 2017-03-16T23:00:00.000Z

JDBC Prepared statement Timestamp issues [duplicate]

I have to store UTC dateTime in DB.
I have converted the dateTime given in specific timezone to UTC. for that I followed the below code.
My input dateTime is "20121225 10:00:00 Z" timezone is "Asia/Calcutta"
My Server/DB(oracle) is running in the same timezone(IST) "Asia/Calcutta"
Get the Date object in this specific Timezone
String date = "20121225 10:00:00 Z";
String timeZoneId = "Asia/Calcutta";
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z");
//This date object is given time and given timezone
java.util.Date parsedDate = dateFormatLocal.parse(date + " "
+ timeZone.getDisplayName(false, TimeZone.SHORT));
if (timeZone.inDaylightTime(parsedDate)) {
// We need to re-parse because we don't know if the date
// is DST until it is parsed...
parsedDate = dateFormatLocal.parse(date + " "
+ timeZone.getDisplayName(true, TimeZone.SHORT));
}
//assigning to the java.sql.TimeStamp instace variable
obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime()));
Store into DB
if (tsSchedStartTime != null) {
stmt.setTimestamp(11, tsSchedStartTime);
} else {
stmt.setNull(11, java.sql.Types.DATE);
}
OUTPUT
DB (oracle) has stored the same given dateTime: "20121225 10:00:00 not in UTC.
I have confirmed from the below sql.
select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable
My DB server also running on the same timezone "Asia/Calcutta"
It gives me the below appearances
Date.getTime() is not in UTC
Or Timestamp is has timezone impact while storing into DB
What am I doing wrong here?
One more question:
Will timeStamp.toString() print in local timezone like java.util.date does? Not UTC?
Although it is not explicitly specified for setTimestamp(int parameterIndex, Timestamp x) drivers have to follow the rules established by the setTimestamp(int parameterIndex, Timestamp x, Calendar cal) javadoc:
Sets the designated parameter to the given java.sql.Timestamp value, using the given Calendar object. The driver uses the Calendar object to construct an SQL TIMESTAMP value, which the driver then sends to the database. With a Calendar object, the driver can calculate the timestamp taking into account a custom time zone. If no Calendar object is specified, the driver uses the default time zone, which is that of the virtual machine running the application.
When you call with setTimestamp(int parameterIndex, Timestamp x) the JDBC driver uses the time zone of the virtual machine to calculate the date and time of the timestamp in that time zone. This date and time is what is stored in the database, and if the database column does not store time zone information, then any information about the zone is lost (which means it is up to the application(s) using the database to use the same time zone consistently or come up with another scheme to discern timezone (ie store in a separate column).
For example: Your local time zone is GMT+2. You store "2012-12-25 10:00:00 UTC". The actual value stored in the database is "2012-12-25 12:00:00". You retrieve it again: you get it back again as "2012-12-25 10:00:00 UTC" (but only if you retrieve it using getTimestamp(..)), but when another application accesses the database in time zone GMT+0, it will retrieve the timestamp as "2012-12-25 12:00:00 UTC".
If you want to store it in a different timezone, then you need to use the setTimestamp(int parameterIndex, Timestamp x, Calendar cal) with a Calendar instance in the required timezone. Just make sure you also use the equivalent getter with the same time zone when retrieving values (if you use a TIMESTAMP without timezone information in your database).
So, assuming you want to store the actual GMT timezone, you need to use:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);
With JDBC 4.2 a compliant driver should support java.time.LocalDateTime (and java.time.LocalTime) for TIMESTAMP (and TIME) through get/set/updateObject. The java.time.Local* classes are without time zones, so no conversion needs to be applied (although that might open a new set of problems if your code did assume a specific time zone).
I think the correct answer should be java.sql.Timestamp is NOT timezone specific. Timestamp is a composite of java.util.Date and a separate nanoseconds value. There is no timezone information in this class. Thus just as Date this class simply holds the number of milliseconds since January 1, 1970, 00:00:00 GMT + nanos.
In PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
Calendar is used by the driver to change the default timezone. But Timestamp still holds milliseconds in GMT.
API is unclear about how exactly JDBC driver is supposed to use Calendar. Providers seem to feel free about how to interpret it, e.g. last time I worked with MySQL 5.5 Calendar the driver simply ignored Calendar in both PreparedStatement.setTimestamp and ResultSet.getTimestamp.
The answer is that java.sql.Timestamp is a mess and should be avoided. Use java.time.LocalDateTime instead.
So why is it a mess? From the java.sql.Timestamp JavaDoc, a java.sql.Timestamp is a "thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value". From the java.util.Date JavaDoc, "the Date class is intended to reflect coordinated universal time (UTC)". From the ISO SQL spec a TIMESTAMP WITHOUT TIME ZONE "is a data type that is datetime without time zone". TIMESTAMP is a short name for TIMESTAMP WITHOUT TIME ZONE. So a java.sql.Timestamp "reflects" UTC while SQL TIMESTAMP is "without time zone".
Because java.sql.Timestamp reflects UTC its methods apply conversions. This causes no end of confusion. From the SQL perspective it makes no sense to convert a SQL TIMESTAMP value to some other time zone as a TIMESTAMP has no time zone to convert from. What does it mean to convert 42 to Fahrenheit? It means nothing because 42 does not have temperature units. It's just a bare number. Similarly you can't convert a TIMESTAMP of 2020-07-22T10:38:00 to Americas/Los Angeles because 2020-07-22T10:30:00 is not in any time zone. It's not in UTC or GMT or anything else. It's a bare date time.
java.time.LocalDateTime is also a bare date time. It does not have a time zone, exactly like SQL TIMESTAMP. None of its methods apply any kind of time zone conversion which makes its behavior much easier to predict and understand. So don't use java.sql.Timestamp. Use java.time.LocalDateTime.
LocalDateTime ldt = rs.getObject(col, LocalDateTime.class);
ps.setObject(param, ldt, JDBCType.TIMESTAMP);
You can use the below method to store the timestamp in database specific to your desired zone/zone Id.
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta")) ;
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());
A common mistake people do is use LocaleDateTime to get the timestamp of that instant which discards any information specif to your zone even if you try to convert it later. It does not understand the Zone.
Please note Timestamp is of the class java.sql.Timestamp.
For Mysql, we have a limitation.
In the driver Mysql doc, we have :
The following are some known issues and limitations for MySQL
Connector/J: When Connector/J retrieves timestamps for a daylight
saving time (DST) switch day using the getTimeStamp() method on the
result set, some of the returned values might be wrong. The errors can
be avoided by using the following connection options when connecting
to a database:
useTimezone=true
useLegacyDatetimeCode=false
serverTimezone=UTC
So, when we do not use this parameters and we call setTimestamp or getTimestamp with calendar or without calendar, we have the timestamp in the jvm timezone.
Example :
The jvm timezone is GMT+2.
In the database, we have a timestamp : 1461100256 = 19/04/16 21:10:56,000000000 GMT
Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "");
props.setProperty("useTimezone", "true");
props.setProperty("useLegacyDatetimeCode", "false");
props.setProperty("serverTimezone", "UTC");
Connection con = DriverManager.getConnection(conString, props);
......
Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4"));
......
rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter)
rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT
rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone
The first method returns : 1461100256000 = 19/04/2016 - 21:10:56 GMT
The second method returns : 1461100256000 = 19/04/2016 - 21:10:56 GMT
The third method returns : 1461085856000 = 19/04/2016 - 17:10:56 GMT
Instead of Oracle, when we use the same calls, we have :
The first method returns : 1461093056000 = 19/04/2016 - 19:10:56 GMT
The second method returns : 1461100256000 = 19/04/2016 - 21:10:56 GMT
The third method returns : 1461085856000 = 19/04/2016 - 17:10:56 GMT
NB :
It is not necessary to specify the parameters for Oracle.
It is specific from your driver. You need to supply a parameter in your Java program to tell it the time zone you want to use.
java -Duser.timezone="America/New_York" GetCurrentDateTimeZone
Further this:
to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM')
May also be of value in handling the conversion properly. Taken from here
If your problem is to get a timestamp of the local zone, you can use this:
Timestamp.from(Instant.now()).toLocalDateTime()

How to show time depend on timezone in java 8 and spring 4?

I'm working on site that is writing on java 8 and spring 4, we are using java 8 standard time api, now on pages always is shown server time (in user profile is shown date of his registration). With old java time api there was way use SimpleDateFormat, but it doesn't fit now. Is there a way to convert server time to client time in jsp pages or in controllers?
One of the way to handle this is get users timezone String ( GMT , IST etc ) in request ( using AJAX or other relevant technology. )
Now by using new Java 8 Local date API we can achieve this as following:
Step 1 : Get Zone from giving zone query parameter that we got from ajax Using Java 8 ZoneId class. :
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
Step 2: Get current time based on that timezone using LocalTime API like below:
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
LocalDateTime currentTimeInLosAngeles = LocalTime.now(losAngeles );
Step 3 : Get DATETIME of particular zone By Using Java 8 ZonedDateTime class
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
LocalDateTime currentTimeInLosAngeles = LocalTime.now(losAngeles );
ZonedDateTime losAngelsDateTime = ZonedDateTime.of(currentTimeInLosAngeles , losAngeles );

GWT timezone issue

From few days I am fighting with different Timezone issues of server and GWT client. but cannot get any success.
Scenario is Server is in UTC timezone let say Client A is in IST timezone.
When client select a date (with time) I pushed to server but date is automatically changed to server's timezone. I dig around this issue and I found multiple solutions like
create custom serializer (No idea how to do that can't found any proper example)
transfer date as a string to server and convert it to server timezone and store it. and when fetching data convert again from server's timezone to client local timezone. sounds good idea.
So my query is.
Any other solutions?
which is best way to manage this ?
any sample code or link?
Simply format the date in UTC format at client side and pass the date as string to the server and store the data in UTC format in database as well.
On the server side everything would be fine, since formatting the date would use the timezone of the server, which is what the date is stored in. On the client side, however, GWT will use the timezone of the client machine, and so there could be a discrepancy.
Sample code:
DateTimeFormat f = DateTimeFormat.getFormat("MMM dd yyyy");
TimeZoneConstants t = (TimeZoneConstants) GWT.create(TimeZoneConstants.class)
TimeZone est = TimeZone.createTimeZone(t.americaNewYork());
int offset = est.isDaylightTime(date) ? +240 : +300;
TimeZone tz = TimeZone.createTimeZone(offset);
String date = f.format(user.getBirthDate(), est);
There are a few other possible solutions, but one of these two might do the trick.
How do I get GWT DateTimeFormat to display using the server TimeZone, rather than the client's?

Joda DateTime,, Formatting, and Mysql Timestamp

After a week of going through so many examples, and moving from Java Date,
to Calendar, to Joda. I have decided to seek help from other sources.
The problem:
Our table has two fields Date (Timestamp), and TZ (String). The idea is to store
the user's UTC in timestamp, and timezone, well, you get the idea. So basically
we think in UTC, and present the user with the time converted to their
timezone on the front end (ie, using the value store in table.TZ)
Another requirement is to use the proper Object (Date, DateTime whatever).
And not pass a String representation of the date around. The best would
be a valid Long that will be correctly translated by MySQL, without having
to use the FROM_UNIXTIME mysql function in our query.
Code we are using:
public DateTime convertTimezone(LocalDateTime date, DateTimeZone srcTZ, DateTimeZone dstTZ, Locale l) {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withLocale(l);
DateTime srcDateTime = date.toDateTime(srcTZ);
DateTime dstDateTime = srcDateTime.toDateTime(dstTZ);
System.out.println(formatter.print(dstDateTime));
System.out.println(formatter.parseDateTime(dstDateTime.toString()));
return formatter.parseDateTime(formatter.print(dstDateTime));
}
The String output is exactly what we need (ie UTC time, 2013-08-23 18:19:12),
but the formatter.parseDateTime(dstDateTime.toString() is crashing with the following
error. Probably because of the UTC timezone independent info, and milleseconds?:
Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "2013-08- 23T18:19:12.515Z" is malformed at "T18:19:12.515Z"
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:873)
at com.example.business.rate.RateDeck.convertTimezone(RateDeck.java:75)
at com.example.business.rate.RateDeck.WriteData(RateDeck.java:143)
at com.example.business.rate.RateDeck.main(RateDeck.java:64)
Search engine enriched question:
How to format UTC for Joda DateTime.
PS My first SO post, and it feels nice? :)
Thanks in Advance,
The new fixed version:
public Timestamp convertTimezone(LocalDateTime date, DateTimeZone srcTZ, DateTimeZone dstTZ, Locale l) {
DateTime srcDateTime = date.toDateTime(srcTZ);
DateTime dstDateTime = srcDateTime.toDateTime(dstTZ);
return new Timestamp(dstDateTime.getMillis());
}
Nick.
It's simply crashing because the format of the parsed string doesn't match with the format of the formatter.
The formatter parses using the format yyyy-MM-dd HH:mm:ss, and the toString() method of DateTime formats the date it using (as documented) the ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).

Categories