-1

I am getting the time object in the form of a string from a rest service . I need to extract the time and then do some time operation.The given time string is "2015-06-16T14:58:48Z". I tried the below code , to convert the string to the time , however , getting incorrect values.

    String time = "2015-06-16T14:58:48Z";

    SimpleDateFormat formatter = new SimpleDateFormat("YYYY-MM-DD'T'hh:mm:ss'Z'", Locale.US);

    String dateInString = "2015-06-16T14:58:48Z";

    Date date = formatter.parse(dateInString);
    System.out.println("Original String : " + time);
    System.out.println("After converting to time : " + formatter.format(date));

The output that i am getting is as below: Original String : 2015-06-16T14:58:48Z After converting to time : 2015-12-362T02:58:48Z

The converted date somehow is getting wrong value.Please suggest where is the mistake.Thanks.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Anupam
  • 231
  • 3
  • 14
  • 4
    Read the [API documentation of SimpleDateFormat](http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html). `Y` doesn't mean what you think it means. Same for `D`. Same for `h`. And the `Z` is not just a letter. It means "UTC timezone". – JB Nizet Jun 20 '15 at 09:17
  • @Anupam Before posting this kind of problem, **use example code that works**. Then tweak one step at a time towards your desired ends. Your error ( format pattern not matching input string) has already been handled countless times on StackOverflow. – Basil Bourque Jun 20 '15 at 20:09

3 Answers3

3

change SimpleDateFormat to this..

SimpleDateFormat formatter = new SimpleDateFormat(
                "yyyy-MM-dd'T'HH:mm:ssX", Locale.US);
Hiren
  • 1,427
  • 1
  • 18
  • 35
  • The 'Z' part is wrong. He/she should use `yyyy-MM-dd'T'HH:mm:ssX` – JB Nizet Jun 20 '15 at 09:34
  • http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html#iso8601timezone – JB Nizet Jun 20 '15 at 09:35
  • 1
    I live in France, which is in UTC+2. If I parse the date using 'Z' i stead of X, the parsed date will be 2015-06-16T14:58:48+02:00, which is the same as 2015-06-16T12:58:48Z, which is thus two hours before the actual date. – JB Nizet Jun 20 '15 at 09:50
3

You format string has a couple of mistakes:

  • Y means the week year, not the year, which is y
  • D means the day of the year. You should have used d, which means the day of the month.
  • h means a 12-hour notation time of day. Since you have 14 you should use H, which handle a 24-hour notation.

To sum it all up:

SimpleDateFormat formatter = 
    new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.US);
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • 1
    The 'Z' part is wrong. He/she should use `yyyy-MM-dd'T'HH:mm:ssX`. Otherwise, The date will be parsed in the date frmat's timezone instead of the UTC timezone. – JB Nizet Jun 20 '15 at 09:35
  • *"`Y` means the week year, not the year, which is `Y`"* So, the uppercase "Y" means both? :P I guess you meant: "which is `y`". – Tom Jun 20 '15 at 09:41
  • @Tom yup, indeed meant `y`. How embarrassing :-( – Mureinik Jun 20 '15 at 09:42
  • Indeed ... no, just kidding. This happens :). – Tom Jun 20 '15 at 09:42
  • Edit: As @JBNizet commented, the format should end with an `X` to properly handle the timezone. – Mureinik Jun 20 '15 at 09:49
0

java.time

The root cause of the problem is using wrong symbols

  • Y (which specifies week-based-year) instead of y (which specifies year-of-era)
  • D (which specifies day-of-year) instead of d (which specifies day-of-month).
  • h (which specifies clock-hour-of-am-pm) instead of H (which specifies hour-of-day).

Check the documentation page to learn more about these symbols.

Also, note that the legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.

Solution using the modern API:

The modern date-time API is based on ISO 8601 and does not require you to use a DateTimeFormatter object explicitly as long as the date-time string conforms to the ISO 8601 standards. Your date-time string conforms to ISO 8601 standards (or the default format used by OffsetDateTime#parse).

import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2015-06-16T14:58:48Z";
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
        System.out.println(odt);

        // ########################Extract time information########################
        LocalTime time = odt.toLocalTime();

        // You can also get it as time.getHour()
        // Extract other units in a similar way
        int hour = odt.getHour();

        // Also using time.format(DateTimeFormatter.ofPattern("a", Locale.ENGLISH));
        String amPm = odt.format(DateTimeFormatter.ofPattern("h a", Locale.ENGLISH));

        System.out.println(time);
        System.out.println(hour);
        System.out.println(amPm);
    }
}

Output:

2015-06-16T14:58:48Z
14:58:48
14
2 PM

Note:

  1. The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
  2. For any reason, if you need to convert this object of OffsetDateTime to an object of java.util.Date, you can do so as follows:
    Date date = Date.from(odt.toInstant());

Learn more about the 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