Date conversation with time zone information - spring-boot

I have one issue. Solutions might be there already in this forum but I couldn't find anything. Please share if it's already answered.
The scenario is as below.
Request is coming in CET to my application which is running in UTac time zone. My backend stored procedure is running in CET zone. The time that is passed in as string with cet offset I need to send same as SQL date with same date to my backend.
Current implementation is:
Convert string date to offsetdate. Then create Instant from that offsetdate and then util date using that instant. Once I have until date I am converting that to SQL Date.
So here issue is if input request us 2012-07-15T00:00:00+02:00 then when applications which is running in UTC is giving correct offset date with cet offset information but when it is converting to instant then always UTC will come. So new date is 2012-07-14T00:00:00Z and because if this my util and SQL date is also coming 1 day behind.
Can anyone please guide if there is any other way where I can create SQL or util. Date for same date irrespective of any time zone?
Because the expectation is request can come with any time zone and we need to understand that zone and then convert or use accordingly and same date should go to back end.
API developed with: Spring boot with JAVA 8 and backend we are accessing using stored procedure where stored procedure is expecting in SQL date.

Since you can use OffsetDate and other classes from java.time, the modern Java date and time API, you should no longer be using java.util.Date nor java.sql.Date. Those classes are poorly designed and long outdated, and the modern API offers all the functionality you need. You might have thought that you needed a java.sql.Date for storing into your SQL database. But with JDBC 4.2 (or a newer JPA implementation such as Hibernate) you can directly store a LocalDate there, which you will prefer.
String requestString = "2012-07-15T00:00:00+02:00";
OffsetDateTime dateTime = OffsetDateTime.parse(requestString);
LocalDate date = dateTime.toLocalDate();
System.out.println("Date is " + date);
This prints:
Date is 2012-07-15
No day has gone lost. To save do for example:
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table (your_date) values (?);");
ps.setObject(1, date);
ps.executeUpdate();
Sometimes we need to pass an old-fashioned type to a legacy API that we cannot afford to change right away. If this was your reason for wanting a java.sql.Date, convert like this:
java.sql.Date sqlDate = java.sql.Date.valueOf(date);
System.out.println("Old-fashioned java.sql.Date is " + sqlDate);
Old-fashioned java.sql.Date is 2012-07-15
Still no day is lost.
Edit: If what your legacy API requires is a java.util.Date, you will need to know the way to convert:
Instant startOfDay = date.atStartOfDay(ZoneId.systemDefault()).toInstant();
Date oldFashionedUtilDate = Date.from(startOfDay);
System.out.println("As old-fashioned java.util.Date: " + oldFashionedUtilDate);
When I run with a default time zone UTC the output is:
As old-fashioned java.util.Date: Sun Jul 15 00:00:00 UTC 2012

Related

Easiest way to access .NET TimezoneInfo from Asp classic page [duplicate]

I'm trying to change some old .asp files with vbs. Our database is going to be converted to store dates in UTC, but on webpages it should show dates and time in "Europe/Helsinki" timezone(
TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time")
in c#). How can I cast the UTC date I get from db query( the query is run in the .asp file as well and the result put into table) to correct date time using vbscript?
Just offset the UTC dates using DateAdd().
Const EETOffset = -2 'EET offset from UTC is -2 hours
Dim dbDateValue 'Assumed value from DB
Dim newDate
'... DB process to populate dbDateValue
newDate = DateAdd("h", EETOffset, dbDateValue)
Note: One problem with this approach is you will also have to compensate for EET and EEST (Eastern European Summer Time) manually based on the time of year. Which is also more difficult when you take into consideration some places don't use it and use EET all year round instead.
See EET – Eastern European Time (Standard Time).
Depending on the RDMS you are using you should even be able to manipulate the dates before they get to the page as part of the initial query.
Useful Links
Format current date and time
How to format a datetime with minimal separators and timezone in VBScript?

Date timezone getting changed when using spring boot default jackson mapping

I have spring boot rest service which call another service xyz and receive date in format yyyy-MM-ddXXX from json. But time Zone of of date is getting changed in my service response. Suppose I am getting date in JSON from service xyz as "date": "2018-08-27-07:00" but my service response is returning date : "2018-08-27-04:00". Offset getting changed. Date field in my POJO is . I want to use the same offset I am getting from backend service and it can be any offset.
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-ddXXX")
private Calendar date;
The problem is that Calendar (and Date) use implicit time conversions to adjust it to your time zone. And almost always it is something that not expected.
To avoid this use java.time classes (such as OffsetDateTime or ZonedDateTime, or even LocalDateTime if you do not need to work wit time zones).
And small offtopic advice: try to use time format aligned to ISO8601 standard (like 2018-08-24T22:30:00)

Spring Boot - Jackson - datetime timezone problems

I am having trouble dealing with timezones across my projects.
First of all, I have two use cases:
1) A user input a DateTime with datepicker in HTML and we want to save it without timezone in the database. example input: 10.04.2018 18:00 --> we want to save exactly this date and also want to retrieve exactly this date, no matter what the timezone is on the client side. (we can think about this like a never changing date string)
2) The more common, second use case is, we enter a DateTime with datepicker in HTML and want to save the date with timezone in the database. For example:
The Clients Timezone is Europe/Istanbul and he inputs a DateTime: 10.04.2018 18:00. Now we want to save this date as Europe/Berlin in Database which would be 10.04.2017 17:00. When we retrieve the date we want to convert the date to the timezone of the client. In this example, if a client with timezone Europe/Berlin wants to retrieve the database date 10.04.2017 17:00 we would exactly retrieve: 10.04.2017 17:00. But if a client with timezone Europe/Istanbul wants to retrieve the same value 10.04.2017 17:00 we would retrieve: 10.04.2018 18:00
Now I tried to achieve this behavior by settings the webapp timezone to Europe/Berlin and parse the dates for each use case with the Moment.js library on client site. Therefore, I always expect to retrieve a Date in the timezone Europe/Berlin from my web service and then either convert to the local time zone or let the date as it is.
I am using Spring Boot with following version:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
In my application.properties file i set those values:
spring.jpa.properties.hibernate.jdbc.time_zone=Europe/Berlin
spring.jackson.deserialization.adjust-dates-to-context-time-zone=false
spring.jackson.time-zone=Europe/Berlin
MyApplication:
#PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
}
My attributes in my model class look like this:
#Column(name = "timeFrom")
#Temporal(TemporalType.TIMESTAMP)
private Date timeFrom;
#Column(name = "timeTo")
#Temporal(TemporalType.TIMESTAMP)
private Date timeTo;
For the first use case, where I want a date which is not parsed to the local time zone i use this code to retrieve my date in javascript: (because I know that my date in database is Europe/Berlin, I convert it to this time zone in order to retrieve the exact same date as it is in the database)
var countHours = moment(timeTracking["countHours"]).tz('Europe/Berlin').format('HH:mm');
For the second use case, where i want to convert my Europe/Berlin date from the database to the local client time zone i use this code:
var timeFrom = moment(timeTracking["timeFrom"]).format('YYYY-MM-DD HH:mm');
When i pass a date from javascript via JSON and ajax to my backend i use this:
moment($("#timeRecord-timeFrom").val()).valueOf()
On serverside i receive a timestamp in milliseconds and i parse it like that:
Date dateFrom = new Date(node.get("startTime").asLong());
Now the weird part: everything I posted above is working perfectly fine on my localhost (local machine). However, as soon as I push my war file to the live system (Jelastic Spring Boot Server) I have an offset of 2 hours in my date.
The strangest part is when I commit my date via ajax and retrieve the persisted object afterward everything is fine and I have no offset. But when I do a full page reload, I immediately receive the date with 2 hours offset. However, the date is still correct in the database.
As this is only happening on the live system and not on the localhost I have no clue how to fix this.
What am I doing wrong? Would it be better to switch to JodaTime or Java8 LocalDateTime? I already tried it but ran into several build errors so stick with java.util.Date.
A best practice tutorial for my use cases would be also appreciated.

Should I store the local time for events instead of UTC?

I am currently storing events of some entities in UTC time but I am not sure if I should do that in this case. Imagine there's an event at 10pm local time (-4h UTC) and a mobile App fetches "todays events". This could e.g. look like this:
App sends request to fetch all clubs in the near location
After receiving all clubs it sends a request to get all events for today. It therefore sends the local time Sun. 10pm to the server.
The server would convert the local time of the mobile device to UTC Mon. 1am and fetch all events from Monday. But of course that was not what I wanted.
Fetching all events from the clubs and convert them to their local time using their local time offset information is not really a great solution.
So wouldn't it be better to just store all events in local time? In that case the mobile App would send its local time to the server which would be able to query all events from the clubs in local time as well.
This sounds much simpler to me but I am not sure if I overlook something.
So what would I do in this case?
Yes, storing everything in UTC is probably the best solution.
You don't say how you are "storing" the dates/times, but if you are using Dates or Joda equivalents, then you should know that their underlying representation is effectively in UTC (they represent a moment in time as an offset in milliseconds since the "Epoch", which is Midnight, Jan 1, 1970 UTC). These dates only have a timezone when you format them as Strings.
Most databases do something similar (store the date in a common timezone, usually UTC). The major exception that I've found is the generally available date-time related column types in MS SqlServer which by default store everything in the local timezone of the server.
Also be aware that if you use SQLite, and you store a date/time by passing a String in SQL that contains a timezone, SQLite will store it without warning, but will ignore the timezone and assume that the timezone is UTC, giving you a result other than what you might expect.
For more on this, see my (old) blog post at http://greybeardedgeek.net/2012/11/24/java-dates/
The other answer is correct. Some more thoughts here.
A time zone is more than the offset from UTC mentioned in the Question. A time zone is also the set of past, present, and future rules for anomalies such as Daylight Saving Time. You should refer to a time zone by its proper name, continent plus Slash plus city or region. Never use the 3-4 letter codes such as EST or IST.
To search for events in the user's "today", you must know the user’s time zone. For example, a new day dawns earlier in Paris than in Montréal. After the stroke of midnight in Paris we still have a few hours of “yesterday” left to go in Montréal.
While you can make a guess as to the user’s time zone, the most reliable way is to ask the user.
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTimeZone now = DateTimeZone.now( zone );
DateTime today = now.withTimeAtStartOfDay();
DateTime tomorrow = today.plusDays( 1 );
// Search for events that start >= today AND that start < tomorrow.
To search Joda-Time objects, use the Comparator built into DateTime. That comparator works across objects of various time zones.
To query a database, convert that pair of DateTime objects into java.sql.Timestamp objects. You do that by extracting and passing the count of milliseconds since the epoch of 1970 in UTC.
long m = today.getMillis();
java.sql.Timestamp tsToday = new java.sql.Timestamp( m );

UTC DateTime problems

I currently store all dateTimes in the DB as UTC dates. Each users time zone offset is also stored in the DB. When I retrieve a Date it is converted back to their local date using this offset.
The problem occurs when I retrieve a date using an ajax call. The date (which is already converted using the offset) is, I think, returned as a Java Date object. The browser then decides to mess with my Date adding the clients computers time zone offset to the Date object. This is causing dates to be a day ahead of what they should be if the time component is more than 11.59am.
The only solution I can come up with is to pass them as strings in which case this of course wouldn't happen. This is a laaaast resort for me though and I would love to find a better solution or workaround for this problem.
Your browser is not messing with the dates given that browsers don't have a native date transfer variable. You have something else that is doing that. How are you sending your dates in ajax? Json? Json will only send numbers or strings. XML will only send strings.
Something is converting your sent date into a javascript date object, find out what it is.

Resources