0

I am converting Date from String type Date to Date type Date,using SimpleDateFormat but the resulting date I am getting is getting changed.can anyone tell me why its changing Also what should i use to get the correct Date type date from String and not the changed one as I am getting here.

    Date d = null;
    String startTime="2012-03-17 16:00:00 PM";
    DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
    try {
          d=  sdf.parse(startTime);
         } catch (ParseException e) {}

System.out.println("DD="+d) //printing Sun Mar 18 04:00:00 IST 2012 ? why this 
   //Date enterd was 17 Mar 2012
saum22
  • 884
  • 12
  • 28
  • 2
    I'm surprised that works at all, given that you're using `hh` (in the range 1-12) with a value of 16. – Jon Skeet Jan 21 '13 at 17:04
  • You specified the AM/PM cycle. Which is based on 12 hours, not 24. – Perception Jan 21 '13 at 17:04
  • @Jon Skeet: It's not really surprising. `DateFormat` is by default operating with a "lenient" Calendar, so that overflowing a field will cause the next more significant field to be incremented while trying to get the set field within the valid range. – jarnbjo Jan 21 '13 at 17:16

4 Answers4

2

It is ambigous if you combine a 24h clock and an AM/PM marker. In your case you should either use "HH" (capital H) to parse the hour field in the range 0-23 and ignore the AM/PM suffix or use a 12h-clock with appropriate AM/PM suffix (in your case "04:00:00 PM").

jarnbjo
  • 33,923
  • 7
  • 70
  • 94
2

You have got a wrong Date-Time string as the input.

AM/PM marker is not applicable for the 24-Hour format of time. It should be either 2012-03-17 04:00:00 PM or 2012-03-17 16:00:00.

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Also, quoted below is a notice from the home page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

Solution using java.time, the modern Date-Time API:

Let's first try to do it the way you have done:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String startDateTime = "2012-03-17 16:00:00 PM";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd hh:mm:ss a", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse(startDateTime, dtf);
        System.out.println(ldt);
    }
}

Output:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2012-03-17 16:00:00 PM' could not be parsed: Invalid value for ClockHourOfAmPm (valid values 1 - 12): 16

As you can see, the java.time API correctly throws an exception informing you about the problem. SimpleDateFormat, on the other hand, parses the input string erroneously.

Now, let's see how you can parse it correctly. In order to parse it correctly, we will use:

  1. The format, uuuu-MM-dd HH:mm:ss where H specifies the 24-Hour format. For your Date-Time string, you can use y instead of u but I prefer u to y.
  2. The function, DateTimeFormatter#parse(CharSequence, ParsePosition) with the ParsePosition index set to 0.

Demo:

import java.text.ParsePosition;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String startDateTime = "2012-03-17 16:00:00 PM";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
        ParsePosition pp = new ParsePosition(0);
        LocalDateTime ldt = LocalDateTime.from(dtf.parse(startDateTime, pp));
        System.out.println(ldt);
    }
}

Output:

2012-03-17T16:00

ONLINE DEMO

Note: Never use SimpleDateFormat or DateTimeFormatter without a Locale.

Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
1

16:00:00 PM is not a valid time and SimpleDateFormat will convert it to the next day at 4:00am.

obourgain
  • 8,856
  • 6
  • 42
  • 57
1

You're using hh in your format string, which is a 12-hour format. That makes sense, given that you've got an AM/PM designator (a) as well... but it doesn't make sense for a value of 16.

I suspect at that "16 o'clock pm" is translating to 4am the following day, hence the problem. (Oddly enough, using setLenient(false) doesn't pick up this error.)

Either use a format of "yyyy-MM-dd HH:mm:ss" and make sure you haven't got " PM" at the end, or use your existing format but give it sensible values (04 instead of 16).

Additionally, I would suggest:

  • Using Joda Time is generally a good idea for date/time work in Java
  • Don't swallow ParseException like this. Empty catch blocks are a really bad idea.
  • When you call Date.toString() that always uses the default time zone, and you can't change the output format. That's okay sometimes, for quick diagnostics, but it can give a misleading impression that the Date actually has time zone information, when it doesn't.
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194