2

I have a text file(CSV) with data in it from MySQL it has many fields and one of the fields is DateOfTransaction with value like this "21/08/2012". I have written a java program to read the CSV file and insert the document in mongodb. code to insert date

    SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); //set the date format
    Date d2 = new SimpleDateFormat("dd/mm/yyyy").parse(arr[10]);
    bookRenterLineItemInstance.setDateoftransaction(d2.getTime());

Every thing is fine in parsing adn dateobject iscorrectly created. But when i query the mongodb collection it give me record with one day behind.

example if i insert date : "21/08/2012"

saved in mongodb as : "DateOfTransaction" : ISODate("2012-01-20T18:38:00Z")

All my queries are related to this field. Please help so that the date is not changed and saved as ISODate("2012-01-21T18:38:00Z") for "21/08/2012"

1

2 Answers 2

4

There are two issues with what you're currently trying to do:

  1. You have a typo in the second line of code which means your months are being parsed as minutes
  2. As mentioned, you're not taking into account timezone.

To address the first problem, you need to change

Date d2 = new SimpleDateFormat("dd/mm/yyyy").parse(arr[10]);

to

Date d2 = new SimpleDateFormat("dd/MM/yyyy").parse(arr[10]);

Date formats are case sensitive, what you were trying to do is to parse the month as a **m**inute instead of a **M**onth. In the test I ran, that meant the months were all coming out as January, which I can see was happening in your example as well. Also, I notice that your first line of code, the formatter (which IS set up correctly) is not used.

The second problem is that yes, Java Dates don't behave the way you expect. They MUST have a time component, even though you don't care about it for simply the date. In addition, they must have a timezone since they have a time.

You might not have the choice of moving to the superior Joda library, in which case there are ways to work around this. I've written a test which should demonstrate this:

@Test
public void shouldParseDateCorrectly() throws Exception {
    // Given
    SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
    format.setTimeZone(TimeZone.getTimeZone("UTC"));

    // When
    Date parsedDate = format.parse("21/08/2012");

    // Then
    Assert.assertThat(parsedDate.toString(), is("Tue Aug 21 02:00:00 CEST 2012"));
    Assert.assertThat(parsedDate.toGMTString(), is("21 Aug 2012 00:00:00 GMT"));
}

So you can see that I've used the correct format, but also set its timezone to UTC (so it has an offset of zero and no daylight savings). Then when you parse the date with this formatter, the date will come out with a time that's midnight in the UTC timezone. Because my computer is in Europe, when I print this date it shows a time of 2am, because this timezone is 2 hours ahead of UTC. But when I use the deprecated toGMTString method, the time comes out as zero.

When you store this date into MongoDB using the Java driver, it will save the date, the time and the timezone with it, even if all you care about is the date. What you'll need to do when you read the dates back out again is to remember they're in UTC and set the timezone appropriately.

Alternatively, you can store them in MongoDB without changing the timezone, provided you'll always read them in and write them out in the same timezone. But this is fraught with unexpected bugs when a) dealing with times over midnight and b) daylight savings time kicks in (or stops).

Or just use Joda-Time.

Sign up to request clarification or add additional context in comments.

Comments

1

I don't know MongoDB. But persisting date-times in UTC (no time zone offset) is common and advisable. Simply use that stored value to reconstitute your object and set the desired time zone.

Use Joda-Time rather than the notoriously bad java.util.Date/Calendar classes.

Your question fails to address the issue of time zone. If you ignore time zone, you'll be getting the default which can lead to unexpected behavior in production. Always specify the desired time zone.

Seems that MongoDB understands ISO 8601 formatted strings.

Here is some example Java code showing how to convert from your date string to a Joda-Time DateTime object. From there adjust to UTC. Then render a string in ISO format. And back again to a DateTime object. Finally to a java.util.Date if necessary to share with other classes.

Example Code

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;

String dateString = "21/08/2012";

DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );

DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd/MM/yyyy" ).withZone( timeZone );

// If focusing on the day rather than a particular time of day, set time portion to first moment of day.
// Do not assume the beginning of day is zero hours. Daylight Saving Time may affect that.
DateTime dateTime_Kolkata = formatter.parseDateTime( dateString ).withTimeAtStartOfDay();
DateTime dateTime_UTC = dateTime_Kolkata.toDateTime( DateTimeZone.UTC );
String dateTime_UTC_AsString = dateTime_UTC.toString(); // Renders ISO 8601 string by default.

// Perhaps pass that string to MongoDB.

// Reconstitute a DateTime instance from ISO 8601 string.
// DateTime constructor interprets ISO format, so no need to parse through a formatter.
DateTime dateTimeReconstituted = new DateTime( dateTime_UTC_AsString, timeZone );

// Convert to a java.util.Date only if required for interaction with other classes.
java.util.Date date = dateTimeReconstituted.toDate();

Dump to console…

System.out.println( "dateTime_Kolkata: " + dateTime_Kolkata );
System.out.println( "dateTime_UTC: " + dateTime_UTC );
System.out.println( "dateTime_UTC_AsString: " + dateTime_UTC_AsString );
System.out.println( "dateTimeReconstituted: " + dateTimeReconstituted );
// Confusingly, java.util.Date has no time zone yet renders a string using Java environment's default time zone.
System.out.println( "date: " + date );

When run…

dateTime_Kolkata: 2012-08-21T00:00:00.000+05:30
dateTime_UTC: 2012-08-20T18:30:00.000Z
dateTime_UTC_AsString: 2012-08-20T18:30:00.000Z
dateTimeReconstituted: 2012-08-21T00:00:00.000+05:30
date: Mon Aug 20 11:30:00 PDT 2012

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.