Trying to save Date in Mongo db in java apllication but it is saving one day before i have tried code mentioned below.
I tried creating a custom conversion using Zonal Date Time Converter please help if someone has faced issue like that.
#Bean
public CustomConversions customConversions(){
List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();
converters.add(new DateToZonedDateTimeConverter());
converters.add(new ZonedDateTimeToDateConverter());
return new CustomConversions(converters);
}
#Bean
public MongoTemplate getMongoTemplate() throws UnknownHostException {
MappingMongoConverter converter = new MappingMongoConverter(
new DefaultDbRefResolver(getMongoDbFactory()), new MongoMappingContext());
converter.setCustomConversions(customConversions());
converter.afterPropertiesSet();
return new MongoTemplate(getMongoDbFactory(), converter);
}
class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
#Override
public ZonedDateTime convert(Date source) {
return source == null ? null : ofInstant(source.toInstant(), systemDefault());
}
}
class ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {
#Override
public Date convert(ZonedDateTime source) {
return source == null ? null : Date.from(source.toInstant());
}
}
MongoDB will convert your date to GMT time during saving. But if you pull your date again to local time zone you will have appropriate time.
If you have application intended for different geo locations with different zones you could use GMT time zone on backend and local time zone on frontend. If zone is important for your business case you can save in mongodb both GMT time and zone separately.
You will not be able to save zone inside date object in MongoDB.
Its just looks bad but its good and I will try to explain.
Suppose you want to save date from:
Germany/Berlin as local date 2019-09-20T00:20:00.000 GMT+1
MongoDB will convert this date to GMT and you will see in database ISODate("2019-09-19T23:20:00.000Z") (look like one day before same as
you describe)
If you fetch this mongo document and deserialize to Java object with
date you could print date and you will see:
In Germany and GMT+1 locations you will print what you expect 2019-09-20T00:20:00.000 GMT+1 because Java java.util.Date automatically convert GMT to local time
In other locations you will see other times for example in London you will see 2019-09-19T23:20:00 GMT and its ok because London is 1
hour before Berlin
Solution depending of your case but common mistake is date picker which provide local date with time 00:00 and conversion create problems. In this case just send UTC date from frontend side.
You have 2 common cases:
You need to save time of online call (you don't need location, some members will be from Japan, some from Germany and some from Brasil)
In this case you could send local time from your time picker and mongo will convert to GMT. When clients fetch dates you will return UTC and they will have automatic conversion to local times and all clients will see correct time
You need to save time of face to face appointment (you need to save location because some members will be from Japan, some from Germany and some from Brasil and suppose they have to know what is local time)
In this case you could save date in one field and tiemzone in second filed. This will ensure what you want.
If you have some another case or some another problem please share more details.
Related
I'm about to deal with time zones in Grails (Java). Here Java 7 is used and Grails 2.3.7.
I have a WebApp where each user is assigned a timeZoneID. If a user enters a date, it only consists of day, month and year. I want to set the time automatically.
The date entered by the user (e.g. 01.10.2018, german format) should be saved in the DB (MySQL) in UTC format.
When the date is displayed to the user, it is formatted according to the user's time zone.
Many timeZoneIDs work fine with my code (Europe/Berlin, Hont_Kong, ....), but America/New_York for example doesn't and I don't understand why.
The code to parse and save a date is as follows:
//endDate is 31.10.2018
def format = messageService.getMessage(code: 'default.date.short.format')
//--> dd.MM.yyyy for DE and MM/dd/yy for EN
println("Use format: " + format)
SimpleDateFormat sdf = new SimpleDateFormat(format);
//set timezone (America/New_York)
sdf.setTimeZone(TimeZone.getTimeZone(user.timeZoneID))
//parse endDate
Date parsedEndDate = sdf.parse(endDate)
//create a calendar instance (e.g. America/New_York)
Calendar calendarEnd = Calendar.getInstance(TimeZone.getTimeZone(user.timeZoneID));
//set time
calendarEnd.setTime(parsedEndDate);
//set hour/minute automatically
calendarEnd.set(Calendar.HOUR_OF_DAY, 23)
calendarEnd.set(Calendar.MINUTE, 59)
//at this point it should be 31.10.2018, 23:59 (german format, timezone America/New_York)
//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))
//save the date
def obj = new Foo(date:calendarEnd).save(flush:true)
The code inside my view (gsp) to display a date is as follows:
<g:formatDate
timeZone="${user.timeZoneID}"
date="${fooInstance?.calendarEnd}"
format="${message(code: 'default.date.format', default: 'MM/dd/yyyy, hh:mm a')}"/>
Inside the DB I get 2018-11-01 00:59:00
Inside my view (GSP) it results in 31.10.2018, 19:59, instead of 31.10.2018, 23:59
Thank you very much for your help.
The problem is in convert step:
//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))
Because you are just changing the time zone so it is using the given time and date as if it is the UTC time zone.
Java 1.7 and before are somewhat unwieldy in regards to the Time API so a lot of people use Joda Time.
Otherwise you can use the advice from this question resulting in something like:
calendarEnd.add(Calendar.MILLISECOND, TimeZone.getTimeZone('UTC').getOffset(parsedEndDate.getTime())
This is not tested and could be wrong as the offset calculation might be diffrent
could somebody help or give me some hint with following problem. I have trouble with creating Timestamp in Java. In my db i have timestamp stored in UTC time for example 2016-10-20 23:30:00.000000 and my timezone is Europe/Prague so time is +1 Hour. And if i want to select records from 2016-10-21 i have to select also records from 2016-10-20 23:00:00.000000 if i want to have correct results. I am using Postgresql and JOOQ.
public DateTime getDateTimeWithZone() {
return new DateTime().withZone(MyFormatter.getDateTimeZone());
}
This code is in service class Localization service.
Then in controller i create joda time Interval.
Interval range = new Interval(localizationService.getDateTimeWithZone().withTimeAtStartOfDay(), localizationService.getDateTimeWithZone().withTimeAtStartOfDay().plusDays(1));
This gives me
2016-10-21T00:00:00.000+01:00/2016-10-22T00:00:00.000+01:00
and then in method for selecting records from db via JOOQ i use this construction
Timestamp start = new Timestamp(dtRange.getStartMillis());
Timestamp end = new Timestamp(dtRange.getEndMillis());
and result is
start = 2016-10-21 00:00:00.0
end = 2016-10-22 00:00:00.0
but i need to have start and end one hour back
Also i tried to modify method getDateTimeWithZone() with UTC time
public DateTime getDateTimeWithZone() {
return new DateTime().withZone(DateTimeZone.UTC);
}
range is the same. I think problem is with .withTimeAtStartOfDay() but in this case i need to have .withTimeAtStartOfDay() return 2016-10-20 23:00:00.0000. Is there any way how to do it with joda time or new java.time or write some own implementation od DateTime and override .withTimeAtStartOfDay() to return shifted DateTime. I will appreciate any help.
I am working on Spring MVC project. It is an quasi online system where each client will install our system (Tomcat n Mysql will get installed through an installer) on their machine. They will download the data by connecting their machine to internet. Once data get downloaded they can disconnect from internet.
By considering above scenario, we want to validate the system date n time is correct according to time zone. I have checked How to get local time of different time zones?, The code :
java.util.TimeZone tz = java.util.TimeZone.getTimeZone("IST");
java.util.Calendar c = java.util.Calendar.getInstance(tz);
System.out.println(c.get(java.util.Calendar.HOUR_OF_DAY)+":"+c.get(java.util.Calendar.MINUTE)+":"+c.get(java.util.Calendar.SECOND));
Give the same time of the system. I want something which will tell time according to the time zone. Same as like when we set time zone on OS clock it will automatically set the correct date and time according to that time zone.
Implementation like this:
Date accurateTimeZoneDate = //HERE I WANT SOMETHING TO GET DATE ACCORDING TO TIME ZONE.
Date machineCurrentDate = new Date();
if(accuratetimeZoneDate == machineCurrentDate)
{
//machine date and time zone date is correct.
}
else
{
//machine date and time zone date is NOT correct.
}
Update
We have tried this:
Daily it is mandatory to connect the system to internet so that application will ping to an central ntp and get the time and validate. once validation is successful then they can disconnect from internet. But in this case after validation they switch to some old date and use the expired content.
Ok if you want system time and date then you should try new Date().
it will give current date time with timezone.
Instead of using Calendar, you should use new Date()
System.out.println("Current Date And Time"+ new Date());
In my Android application server will return some UTC date in following format(yyyy-MM-dd HH:mm:ss) 24hours and I need to convert those time into user's TimeZone for example CST, IST.
I did the following code but I do know is it correct or not, please assist me to do the time zone conversion in right way.
I get UTC date as json string and converting into user's time zone format and showing Android side
private static Date utcDate;
private static DateFormat expireFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
try {
expireFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
utcDate = expireFormat.parse("2014-04-01 10:32:00");
System.out.println(TimeZone.getDefault().getID());
expireFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()));
System.out.println(expireFormat.format(utcDate));
} catch (ParseException e) {
e.printStackTrace();
}
output of the code:
Asia/Calcutta
2014-04-01 16:02:00
The overall approach is OK if a re-formatted String is really what you're trying to get.
There are some issues though
SimpleDateFormat is not a threadsafe class. Setting it to a static field inside a server is a problem!
Same as #1 regarding using a static field to hold the intermediate Date object.
Is "CST" China Standard Time? Central Standard Time (US or Australia)? Cuba Standard Time? Three letter abbreviations TimeZone are bad news in general. Try to use an Olson Name or Alias if at all possible.
Is this the server side or the android? If it's a server, you could probably benefit from the new Java 8 API for DateTime handling.
We have a scenario where a user uploads database data. The user reads the data from the database onto java objects and then serialises the java objects into a file. This file is then uploaded to a remote server. On the remote server, I then deserialise this file and put it onto a database on the remote server.
The problem appears when I deserialise timestamps and dates. The timestamps were different when compared to the one on the client system. We traced the problem back to an incorrectly set timezone on the client system. The client was on a Pacific Time US and Canada(UTC - 8:00) and the server was on Indian Time (UTC + 5:30). Hence when the database inserted the data it compensated for the time difference. We changed the incorrectly set timezone on the client system and everything is now fine.
But we dont have control on all the client systems. If they are on a different timezone (set on their system incorrectly) then how do we instruct the server not compensate and store the data as is. Meaning the deserialising should put the data in the DB exactly as sent by the user.
Also, if we move our server to a different timezone, the problem will manifest for all users then.
We use java and the database is mysql
EDIT: Here's a code sample:
public class Test
{
public static void main(String[] args) {
try {
DBObject db = new DBObject();
db.setTs(new Timestamp(System.currentTimeMillis()));
//first save the data on one timezone
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("/Users/Sethu/temp/test.dat"));
os.writeObject(db);
os.close();
//comment the top portion of saving.. change the timezone and run the code,
//you will see a different date appearing in your screen
ObjectInputStream is=new ObjectInputStream(new FileInputStream("/Users/Sethu/temp/test.dat"));
DBObject dbin=(DBObject)is.readObject();
System.out.println(dbin.getTs());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class DBObject implements Serializable{
private Timestamp ts;
public Timestamp getTs() {
return ts;
}
public void setTs(Timestamp ts) {
this.ts = ts;
}
}
Edit 2: In order to convert the date back into the Timezone where it was originally created, I have now change the code to send the Timezone serialised as well. Now the timezone is first serialised object and the DBObject is second one.. Now using the serialised timezone I am trying to change the resonctructed object:
System.out.println("Current Timezone="+DateTimeZone.getDefault());
DateTimeZone timezone=(DateTimeZone)is.readObject();
System.out.println("Timezone of saved object="+timezone);
DBObject dbin=(DBObject)is.readObject();
System.out.println("Date in current timezone="+dbin.getTs());
System.out.println("Date time Object in timezone of saved object="+new DateTime(dbin.getTs()).withZone(timezone));
//This is where the issue is.. As soon as I do this, I get the date in the current timezone again..
System.out.println("Date time exported to date="+new DateTime(dbin.getTs()).withZone(timezone).toDate());
When I do this, this is the output I am getting!
Current Timezone=America/Los_Angeles
Timezone of saved object=+05:30
Date in current timezone=Tue Dec 06 23:30:56 PST 2011
Date time Object in timezone of saved object=2011-12-07T13:00:56.687+05:30
Date time exported to date=Tue Dec 06 23:30:56 PST 2011
I would store all timestamps as GMT on the server and the client. I only change it to the user's preferred time zone when displaying the time. This avoid confusion over which time zone was used to store or retrieve the date/time and was it correct etc.
You can add timezone information on your DBObject as well since the TimeZone class is serializable. To get the current TimeZone, just use Calendar.getInstance().getTimeZone().