mongodb ISODate problems - java

I am using java(IDE is eclipse) to query on mongodb. Below is my java code:
DBObject query = new BasicDBObject();
ObjectId id =new ObjectId("529f280b90ee58cb7732c2b8");
query.put("_id", id);
DBCursor cursor = collection.find(query);
while(cursor.hasNext()) {
DBObject object = (DBObject)(cursor.next());
System.out.println(object.get("_id"));
System.out.println(object.get("createDate"));
}
Problems happened in the createDate whose type is ISODate and value is ISODate("2013-10-21T01:34:04.808Z"), but the println result of my code is 'Mon Oct 21 **09**:34:04 CST 2013', the hour has changed from 01 to 09. I don't know what happened!
Can anybody help?

The hour did not change. You must be in China, given the "CST" in your example and the 8 hour difference. If you interpret "CST" as "China Standard Time" (rather than Central Standard Time in the US), then you have a time zone that is 8 hours ahead of UTC/GMT. So when ti is 1 AM UTC/GMT, at the vary same moment the clock on the wall in Taipei will read "9 AM".
Minor point: Those three-letter codes for time zones are obsolete and should be avoided. They are neither standardized nor unique. Use proper time zone names.
Major point: The problem lies in how you extract a value from MongoDB that represents a date-time.
I don't know MongoDB, and their doc is confusing, so I can't help you much further. If you can retrieve an ISO 8601 string as seen in your first example, that is much preferable to the format of your second example.
If you want to work with the date-time value in Java, you can feed an ISO 8601 string directly to a DateTime constructor in Joda-Time 2.3.
DateTime dateTime = new DateTime( "2013-10-21T01:34:04.808Z" );
Update
This doc says that the Java driver for MongoDB will give you a java.util.Date object. That explains your problem. The java.util.Date & Calendar classes bundled with Java are notoriously bad. One problem is that while a Date instance has no time zone, its toString() method uses the JVM's default time zone to render a string. And Date's toString method uses that terrible ambiguous format.
You should avoid using java.util.Date & Calendar classes. For now use the Joda-Time library. In Java 8, you can use the new java.time.* classes.
You can convert back and forth between java.util.Date and Joda-Time. Pass a Date instance to Joda-Time constructor. To go back, call Joda-Time toDate() format.
Note that while a java.util.Date has no time zone information within it, in contrast a DateTime object does have a time zone assigned. If you want UTC/GMT, specify DateTimeZone.UTC.
Your code should look more like:
java.util.Date date = object.get("createDate");
DateTime createDateTime = new DateTime( date, DateTimeZone.forId( "Asia/Manila" ) );
System.out.println( createDateTime );
… do some work …
java.util.Date dateGoingBackToMongoDB = createDateTime.toDate();

Related

Converting java.sql.Timestamp to Instant Time

From my database i retrieve value as :
20-DEC-17 10.15.53.000000000 AM
I want above java.sql.Timestamp to be converted to Instant time as :
2017-12-20T10:15:53Z
I tried following with current time stamp
Timestamp ts2 = new Timestamp(date1.getTime());
Date tradeDate1=new Date(ts2.getTime());
Instant tradeInstant = tradeDate1.toInstant();
System.out.println("Tade Instant"+ tradeInstant);
Actual time stamp: Fri Jun 22 16:07:35 IST 2018
What is prints in instan : Tade Instant2018-06-22T10:37:35.420Z
The hours/mins/seconds are updated which I dont want - is there a way this can be retained as is?
I am assuming that you are using at least Java 8 and at least JDBC 4.2. I am further assuming that the timestamp doesn’t have time zone or offset information in the database, but is to be understood as a timestamp in UTC (which is a recommended practice). In this case I would consider it safest to add the information about UTC offset explicitly in Java:
PreparedStatement yourPreparedStatement
= yourConnection.prepareStatement("select trade_timestamp from your_table");
ResultSet rs = yourPreparedStatement.executeQuery();
while (rs.next()) {
LocalDateTime tradeDateTime = rs.getObject(1, LocalDateTime.class);
Instant tradeInstant = tradeDateTime.atOffset(ZoneOffset.UTC).toInstant();
System.out.println("Trade Instant: " + tradeInstant);
}
Note that the code avoids the outdated Timestamp class completely. A LocalDateTime is a date and time of day without time zone or offset. If your database datatype had been timestamp with time zone, you could have passed either Instant.class or OffsetDateTime.class to rs.getObject and have got an Instant or an OffsetDateTime back. JDBC 4.2 only specifies support for OffsetDateTime, but many drivers support Instant too. Obviously with Instant you need no further conversion. With OffsetDateTime do
Instant tradeInstant = tradeDateTime.toInstant();
Depending on your database and its capabilities it is also possible that you can set UTC as offset/time zone on the database session so you can get the correct instant even from timestamp without time zone.
Discussion: Arvind Kumar Avinash in a comment recommends that one should rely only on the types officially supported by JDBC 4.2, that is, LocalDateTime and OffsetDateTime for our purposes. The types are mentioned at the bottom of the article Why do we need a new date and time library? on Oracle’s web site, there’s a link at the bottom. Arvind Kumar Avinash further refers us to PSQLException: Can't infer the SQL type to use for an instance of java.time.Instant, also linked to at the bottom. Since comments are fragile, I wanted to include the essence here in the answer.
What went wrong in your code?
It seems your database session understood the timestamp as a date and time in your local time zone (IST, I assume it’s for India Standard Time (other interpretations exist)). According to Mark Rotteveel’s informative comment this behaviour is required by JDBC, but it doesn’t agree with your need when the value is in UTC. Therefore it gave you the wrong point in time, though it looked right when you printed it. The conversion in itself was correct.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Why do we need a new date and time library?
PSQLException: Can't infer the SQL type to use for an instance of java.time.Instant. on doobie’s GitHub page (doobie is a JDBC layer for Scala)
Building from the comment about not using SimpleDateFormat, I have moved to DateTimeFormatter:
Date today = new Date();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss") // same format
.withLocale(Locale.UK) // UK locale
.withZone(ZoneId.systemDefault());
String output = dateTimeFormatter.format( today.toInstant() );
System.out.println( output );
Running gives you:
2018-06-22T14:14:26
I have created a SimpleDateFormat, which only prints "up to seconds":
/* simple date format */
DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
/* get toInstant() and convert to date */
Date myDate = Date.from(today.toInstant());
/* myDate formatted using DATE_FORMAT */
String formattedDate = DATE_FORMAT.format(myDate);
System.out.println(formattedDate);

How to convert MST time zone to IST format and then want to persist that in database in java

I am new to Java. I have a web application that runs on a godaddy server in the USA.
The problem is when we use the application anywhere we need to update the date with the respective timestamp in database. While updating it is storing as MST format date instead of IST format (when I tried from India). Let me know how can I solve this.
Thanks in advance.
My code is as follows.
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
f.setTimeZone(TimeZone.getTimeZone("IST"));
String date = f.format(new Date());
Date aptDate = formatter.parse(date);
System.Out.Print("The IST time is : "+ date);
Here I am getting the string format date, I want to convert into a date object and then store in the database.
When I apply the conversion it is giving earlier date. Let me what is the wrong going.
Your Question is confusing. Here are some guidelines to re-orient your thinking.
You are using old date-time classes now outmoded by the java.time framework built into Java 8 and later. Avoid the old classes as they are poorly designed, confusing, and troublesome.
Stop using the 3-4 letter codes such as IST. Do you mean India Standard Time or Irish? These codes are neither standardized nor unique. Erase these codes from both your thinking and your code. Use proper time zone names in the format of continent/region.
Do most of your work, your business logic, data exchange, data storage, and database in UTC. Apply a time zone only when expected by your user or data sink.
Use date-time types when defining columns in your database. Do not store date-time values as strings.
Use the java.sql types to transfer date-time values in and out of the database. Convert immediately to java.time types. Eventually JDBC drivers will be updated to use java.time types directly. Until that day, use new methods added to the old java.sql classes for convenient conversions.
An Instant is a moment on the timeline in UTC.
Instant now = Instant.now();
Convert to java.sql.Timestamp to write to the database.
java.sql.Timestamp ts = java.sql.Timestamp.from( now );
To the other direction, for retrieval, convert from java.sql to java.time.
Instant instant = myJavaSqlTimestamp.toInstant();
Notice that for database work we do not care about time zone as the values are all in UTC on all sides: Java, JDBC, SQL, database.
To view the wall-clock time for some locality, apply a time zone (ZoneId) to generate a ZonedDateTime object.
ZoneId zoneIdEdmonton = zoneId.of( "America/Edmonton" );
ZonedDateTime zdtEdmonton = ZonedDateTime.ofInstant( instant , zoneIdEdmonton );
You can apply yet another time zone. Note that java.time uses immutable objects. An new object arises from an old object rather than changing (“mutating”) the original. In this example, the zdtEdmonton object begets the zdtKolkata object.
ZoneId zoneIdKolkata = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdtKolkata = zdtEdmonton.withZoneSameInstant( zoneIdKolkata );

Java Date problems with TIMEZONE

I am struggling on this for days.
I have a date field, that gives a date on 'yyyy-MM-dd' format.
My Object have this field like this
#Temporal(TemporalType.DATE)
private Date finishdate;
I am on UTC, and this need to work all over the world, so on UTC-7 or UTC+7
On DataBase this value need to be store with 0 hours.
When the finishdate is filled, the format give me the timezone, so, for example:
I want 2014-10-01, with ZERO HOURS AND MINUTES AND SECONDS, on diferent timezones I catch:
2014-10-01 07:00:00:000
or
2014-09-01 17:00:00:000
The problem seams to be because of the Date liybrary, and i've found a solution with JODA Library, but i was told not to used it, and I need to find another solution.
So, need to convert to UTC Date, all dates,or other thing, but the day must be the same, like 1 October.
Anyone pass through this?
The Joda-Time library fixes issues like this, and I believe that is also the basis of the java.time package in Java 8, but for older Java versions this kind of problem occurs constantly.
The only consistent way I have seen for dealing with this without Joda time is to treat pure dates as a String ("2014-10-01") or Integer type (20141001) instead of a Date. and only convert to dates when needed in calculations. It is a real pain though.
Don't forget that SimpleDateFormat is not thread-safe. The answer saga56 gives may work but you'll have some very weird dates if there's any simultaneous use of the deserialiser. You need to 'new' the SimpleDateFormats each time, or (less favourably) do something else to ensure SimpleDateFormat is strictly limited to 1 thread at a time.
Solution to this issue.
We made an Custom Deserializer to every object of the type Date.
On ObjectMapperFactory, where we serialize or deserialize, i mapped to another class like this:
module.addDeserializer(Date.class, new DateDeserializerByDefault());
Then, on this class we did:
private static SimpleDateFormat dateFormatWithoutTimezome = new SimpleDateFormat("yyyy-MM-dd");
private static SimpleDateFormat dateFormatWithTimezone= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
private static Pattern pattern = Pattern.compile("([0-9]{4})-([0-9]{2})-([0-9]{2})");
#Override
public Date deserialize(JsonParser jparser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String content = jparser.getValueAsString();
DateFormat format=(pattern.matcher(content).matches()) ? dateFormatWithoutTimezome : dateFormatWithTimezone;
try {
return format.parse(content);
} catch (ParseException e) {
throw new JsonParseException("Date parse failed", jparser.getCurrentLocation(),e);
}
}
And with this, when we receive Dates on diferent format, or with timezone to be stor we can change it to what we want.
I Hope this solution can help, I was stuck on this for 3,5 days. Dates are a pain in the a**.
The other Answers are correct but outdated.
java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat. The Joda-Time team also advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
LocalDate
A LocalDate represents a date-only value without time-of-day and without time zone.
Your input string is in standard ISO 8601 format, so it can be parsed directly by LocalDate. No need to specify a formatting pattern.
String input = "2014-10-01";
LocalDate localDate = LocalDate.parse( input );
ZonedDateTime
You assume the day starts at time 00:00:00. But that is not always the case. In some time zones Daylight Saving Time (DST) or possibly other anomalies can mean the day starts at some other time on the clock such as 01:00:00. Let java.time determine the starting time of the first moment of a day. Specify a time zone, and assuming the tz database bundled with Java is up-to-date, then a call to LocalDate::atStartOfDay produces a ZonedDateTime for your date and first moment.
ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = localDate.atStartOfDay( zoneId );
If you want the first moment of the day in UTC, specify the constant ZoneOffset.UTC (ZoneOffset being a subclass of ZoneId).
ZonedDateTime zdt = localDate.atStartOfDay( ZoneOffset.UTC );
Alternatively, use the more appropriate OffsetDateTime class. This is for values with a mere offset-from-UTC but lacking the set of rules for handling anomalies such as DST found in a full time zone. In UTC the day always starts at 00:00:00 which is stored in a constant LocalTime.MIN.
OffsetTime ot = OffsetTime.of( LocalTime.MIN , ZoneOffset.UTC );
OffsetDateTime odt = localDate.atTime( offsetTime );
Database
For database work, if you want a date-only value stored you should be using a data type along the lines of the SQL Standard type of DATE.
For a date-time value, nearly every serious database converts incoming data into UTC for storage in a TIMESTAMP WITH TIME ZONE type column. Your JDBC driver should help with this. But test and experiment as the behavior of drivers and databases varies tremendously.
With JDBC 4.2 and later, you may be able to pass/fetch the java.time types directly via setObject/getObject. If not, convert to java.sql types via new methods added to the old classes.

Convert UTC date into milliseconds

I am not interested in what the current UTC time is in milliseconds, nor do I need to mess with timezones. My original date is already stored as a UTC timestamp.
I have a date stored in a database in UTC time, "2012-06-14 05:01:25".
I am not interested in the datetime, but just the date portion of the it. So, after retrieving the date in Java, and excluding the hours, minutes, and seconds - I am left with "2012-06-14".
How can I convert this into UTC milliseconds?
EDIT: I'd missed the "ignoring the time of day" part. It's now present, but near the end...
The simplest approach is probably to use SimpleDateFormat, having set the time zone appropriately:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = format.parse(text);
long millis = date.getTime();
(Setting the time zone is the important bit here, as otherwise it will interpret the value to be in the local time zone.)
Alternatively, if you're doing anything less trivial than this, use Joda Time which is a much better date/time API. In particular, SimpleDateFormat isn't thread-safe whereas DateTimeFormatter is:
// This can be reused freely across threads after construction.
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
.withLocale(Locale.US)
.withZoneUTC();
// Option 1
DateTime datetime = formatter.parseDateTime(text);
long millis = dateTime.getMillis();
// Option 2, more direct, but harder to diagnose errors
long millis = formatter.parseMillis(text);
Now so far, we've parsed the whole whole caboodle. The easiest way of ignoring the date part is just to round it off - after all, Java doesn't observe leap seconds, so we can just truncate it:
long millisPerDay = 24L * 60L * 60L * 1000L; // Or use TimeUnit
long dayMillis = (millis / millisPerDay) * millisPerDay;
That will "round towards 1970" so if you have a date before 1970 it will round to the end of the day - but I suspect that's unlikely to be a problem.
With the Joda Time version you could just use this instead:
DateTime dateTime = formatter.parseDateTime(text);
long millis = dateTime.toLocalDate().getLocalMillis();
I would personally not go with the idea of just taking a substring. Even though you're not actually interested in preserving the hour/minute/second, I think it's appropriate to parse what you've been given and then throw away information. Aside from anything else, it makes your code fail appropriately with bad data, e.g.
"2012-06-100"
or
"2012-06-14 25:01:25"
indicate problems in whatever's supplying you data, and it's good to spot that rather than to continue blindly just because the first 10 characters are okay.
UPDATE: See the modern solution using java.time classes in the correct Answer by Ole V.V..
Simpler
The answer by Jon Skeet is correct. And he makes a good point about including, rather than truncating, the time-of-day info while parsing.
However, his code could be simplified. Especially so because Joda-Time gained an important new method in the latest versions: withTimeAtStartOfDay. This method supplants all the "midnight"-related classes and methods which are now deprecated.
Specifying a Locale is a good habit, as shown in his code. But in this particular case a Locale is not necessary.
His answer correctly suggests the Joda-Time library, far superior to using java.util.Date, .Calendar, and java.text.SimpleTextFormat. Those classes are notoriously troublesome, and should be avoided. Instead use either Joda-Time or the new java.time package built into Java 8 (inspired by Joda-Time, defined by JSR 310).
First Moment Of The Day
You cannot ignore time-of-day if what you want is a count of milliseconds-since-epoch. I suspect what you want is to change the time to first moment of the day. In UTC, this always means the time 00:00:00.000. But note that in local time zones, the first moment may be a different time because of Daylight Saving Time and possibly other anomalies.
ISO 8601
Your string is nearly in standard ISO 8601 format, but we need to swap a T for the SPACE in the middle. Then we can feed the resulting string directly to Joda-Time as Joda-Time has built-in formatters used by default for standard strings.
Example Code
The following example code assumes the intent of your question is to parse a string as a date-time value in UTC time zone, adjust the time to the first moment of the day, and then convert to number of milliseconds since Unix epoch (beginning of 1970 in UTC).
String inputRaw = "2012-06-14 05:01:25";
String input = inputRaw.replace( " ", "T" ); // Replace SPACE with a 'T'.
DateTime dateTime = new DateTime( input, DateTimeZone.UTC ); // Parse, assuming UTC.
DateTime dateTimeTopOfTheDay = dateTime.withTimeAtStartOfDay(); // Adjust to first moment of the day.
long millisecondsSinceUnixEpoch = dateTimeTopOfTheDay.getMillis(); // Convert to millis. Use a 'long', not an 'int'.
java.time and JDBC 4.2
I am providing the modern answer. These days (and for the last several years) you should use java.time, the modern Java date and time API, for your date and time work. And since JDBC 4.2 you can directly retrieve java.time objects from your database (and also store them into it). A modern JPA implementation (Hibernate at least since Hibernate 5) will be happy to do the same. So forget about SimpleDateFormat, Date and other old classes used in most of the old answers. The mentioned ones are poorly designed, and java.time is so much nicer to work with.
Retrieve proper date-time objects from your database
I also recommend that you don’t retrieve your UTC time as a string from the database. If the datatype in SQL is timestamp with time zone (recommended for UTC times), retrieve an OffsetDateTime. For example:
PreparedStatement pStmt = yourDatabaseConnection
.prepareStatement("select utc_time from your_table where id = 7;");
ResultSet rs = pStmt.executeQuery();
if (rs.next()) {
OffsetDateTime utcDateTime = rs.getObject("utc_time", OffsetDateTime.class);
long millisecondsSinceEpoch = utcDateTime.truncatedTo(ChronoUnit.DAYS)
.toInstant()
.toEpochMilli();
System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);
}
If the type in SQL is dateTime or timestamp without time zone, we probably need to retrieve a LocalDateTime instead (details depending on your JDBC driver and the time zone of your database session). It goes in the same manner. For converting your LocalDateTime to OffsetDateTime, see the conversion below.
If you need to convert from a string
If you cannot avoid getting your UTC time as a string as in the question, parse it into a LocalDateTime and convert from there. For example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String utcTimeString = "2012-06-14 05:01:25";
long millisecondsSinceEpoch = LocalDateTime.parse(utcTimeString, formatter)
.atOffset(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
System.out.println("Milliseconds since the epoch: " + millisecondsSinceEpoch);
Output:
Milliseconds since the epoch: 1339650085000
Link
Oracle tutorial: Date Time explaining how to use java.time.
Use the Date object in combination with SimpleDateFormat.
There is a method named getTime() in Date which will return the milliseconds for you.
Example that solves your problem :
Date truc = new SimpleDateFormat( "y-m-d").parse( "2010-06-14");
System.out.println(truc.getTime());
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd"); //or whatever format you have
Date t = ft.parse('2014-03-20');
String result = String.format("%tQ", t);
System.out.printf("%tQ", t);
There are two methods here:
you put the result milliseconds into a variable result
printing it straight off.
I use a simple and straight forward approach:
Date date = new Date(utcDateInString);
long utcDateInMilliSeconds = date.getTime();

Java data type to hold only date

Which data type in Java can hold just the date and doesn't require a time component? For example, just to store 12/07/2012. I'm working with persisting the data to/from a database that has a date-only data type, so I'm looking for the best equivalent data type in Java.
from the JDK: java.sql.Date:
A thin wrapper around a millisecond value that allows JDBC to identify
this as an SQL DATE value. A milliseconds value represents the number
of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.
To conform with the definition of SQL DATE, the millisecond values
wrapped by a java.sql.Date instance must be 'normalized' by setting
the hours, minutes, seconds, and milliseconds to zero in the
particular time zone with which the instance is associated.
or from JodaTime: DateMidnight or LocalDate (thanks
#cdeszaq)
DateMidnight defines a date where the time component is fixed at
midnight. The class uses a time zone, thus midnight is local unless a
UTC time zone is used.
It is important to emphasise that this class represents the time of
midnight on any given day. Note that midnight is defined as 00:00,
which is at the very start of a day.
The other answers are out-dated.
The old date-time classes are notoriously troublesome and should be avoided.
java.time
The java.time framework is built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality is back-ported to Jave 6 & 7 and further adapted to Android.
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate localDate = LocalDate.of( 2012 , 12 , 7 );
Textual representation
The toString method generates a String using standard ISO 8601 format.
localDate.toString() → 2012-12-07
For other formats use DateTimeFormatter.
SQL
JDBC drivers compliant with JDBC 4.2 can use the getObject and setObject methods to directly fetch/pass the java.time types such as LocalDate to SQL type DATE.
If your driver cannot do so, fall back to using the java.sql types. New methods have been added to the old classes to facilitate conversion.
java.sql.Date sqlDate = java.sql.Date.valueOf( localDate );
And the other direction.
LocalDate localDate = sqlDate.toLocalDate();
Search Stack Overflow
Search Stack Overflow for many more discussions and examples of using java.time. For example, my answer to this similar Question.
Date class. It holds a UNIX timestamp. In most databases, you can specify a field to hold a timestamp as well. You can use DateFormat to format the timestamp however you want.
If you are using Java 8, you can use java.time.LocalDate.
Use Date class that is available.
It shows how hold only date(without time)
formatter = new SimpleDateFormat("dd/MM/yyyy");
Date date= new Date();
Date todayWithOutTime =formatter.parse(formatter.format(date));
Unfortunatelly, java.util.Date is something, that in SQL have name Timestamp. There's no pure type for Date only, javax.sql.Date extends java.util.Date and using this type for date manipulation in Java gives you no advantage.
I'm dealing with this using apache commons-lang class DateUtils:
Date myDate = DateUtils.truncate(timestamp, Calendar.DAY_OF_MONTH);
This will remove the time part and leave only date part.
Use Date class. This is the better way.

Categories