-1

I'm trying to parse 1980-02-22T00:00:00Z into "java.util.Date" using

SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'").parse(stringdate) 

But I got error

caused by: java.text.ParseException: Unparseable date.

How to parse String like this into Date to get time in milliseconds? I've tried to use SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'") and SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")

veben
  • 19,637
  • 14
  • 60
  • 80
Strangelove
  • 761
  • 1
  • 7
  • 29
  • 6
    Please don't use the legacy `java.util.Date` class if you can possibly avoid it. You should instead use the class in the `java.time` package that is appropriate for your use case. – Joe C Nov 22 '18 at 08:04
  • 3
    Since there’s no .SS remove that but keep the ‘Z’? – Sami Kuhmonen Nov 22 '18 at 08:04
  • 1
    I advice you to use class "LocalDateTime" introduced by java 8 instead of "Date" : https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html – veben Nov 22 '18 at 08:11
  • @veben Using java.time is a very good idea (always) and even more so since the string is in ISO 8601 format is, the default format for java.time classes. `LocalDateTime` is not the good choice, though, since you would be losing the offset information that is in the string. Use `Instant` or `OffsetDateTime`. Either will parse the string without any explicit formatter. – Ole V.V. Nov 22 '18 at 11:52
  • Strangelove, the `Z` in your string is no literal, it’s an offset of 0 from UTC, so you need to parse it as an offset, or you will get an incorrect result (in all likelihood). – Ole V.V. Nov 22 '18 at 11:59
  • 1
    `Instant.parse( "1980-02-22T00:00:00Z" )` is all you need. – Basil Bourque Nov 22 '18 at 21:11
  • 1
    FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Nov 23 '18 at 05:50

2 Answers2

6

Just replace:

SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'")

by:

SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
veben
  • 19,637
  • 14
  • 60
  • 80
  • 1
    It works, as in "it does not crash", but it does not, as in "it is not a correct parsing of the date". `Z` in the end is **not** a neutral character. It has a meaning ("the hour is in the UTC time zone"). When you do `SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")` you get a parser that will ignore the 'Z', and treat the hour in the system's timezone, which, of course, is System and User dependant, and not reproducible. In other words, it is a bug. If you want to parse a ISO8601 date, use a ISO8601 parser (e.g. from the XML package or java.time package). – GPI Nov 22 '18 at 08:25
  • 1
    FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Nov 23 '18 at 05:45
2

If you can use java8, you can use LocalDateTime class,

you can do below:

As per suggestions below, I have corrected my code to parse the date.

  String text = "1980-02-22T12:10:02Z";
  LocalDateTime dateTime =  LocalDateTime.ofInstant(Instant.parse(text),ZoneOffset.UTC);
  System.out.println(dateTime);

Result:

1980-02-22T12:10:02
Shiva
  • 1,962
  • 2
  • 13
  • 31
  • 1
    See my comment at @veben's answer. This is a wrong solution, because it ignores the 'Z' in the end, which is a TimeZone information. Therefore, the parsing result may or may not be accurate, depending on the JVM's default timezone (which is system dependant). – GPI Nov 22 '18 at 08:35
  • Agreed, but OP did not mention about if he wanted to convert time into particular timezone. However, I would look into the link you have provided in the question comments and update answer if I can provide more helpful and detailed answer. – Shiva Nov 22 '18 at 09:04
  • 1
    The OP does not have to convert, or even want to convert anything to anywhere. If you System.out.println(date.getMillis()) in your code, set your system clock to London, run it once, then set your system clock to New York, run it again, you'll get different results. Your sample code is system dependant, and 1980-02-22T12:10:02Z is a perfectly defined date that depends on nothing. So, a valid parsing of it should not depend on the system timezone. It is **not** about what the user wants to convert to. It is about making sure the parsing returns the correct point in time in any System setting. – GPI Nov 22 '18 at 09:08
  • Okay - what If I make the change to return `datetime` in `UTC` timezone. so it always returns in UTC irrespective of system settings. so, would it be acceptable? I am saying `UTC` here just for example. – Shiva Nov 22 '18 at 09:15
  • Of course, it would help. But if you want it to really work, you'd have to find if it is UTC or "something else", e.g. if it ends with Z or "+0100" or whatever... Which is the point of my comments. The "Z" means something, and it could be something else than Z, so we can not ignore it. And in the end, you use DateTimeFormatter.ISO_DATE_TIME. – GPI Nov 22 '18 at 09:22
  • As GPI has commented, `LocalDateTime` is exactly the class *not* to use to address this Question. The input string is in standard ISO 8601 format, with the `Z` on the end meaning UTC, pronounced “Zulu”. To ignore the `Z` is is to discard crucial information. The input string represents a moment, a specific point on the timeline. In contrast, the `LocalDateTime` class by definition is not capable of representing a moment, is *not* a point on the timeline. The proper solution here is utterly simple, using the `Instant` class for a moment in UTC: `Instant.parse( "1980-02-22T00:00:00Z" )` – Basil Bourque Nov 23 '18 at 05:47
  • Thank @BasilBourque. I tried to use `Instant` after @GPI suggestion but could not complete it. I will update with this answer with caution that it is only for `UTC`? Does it makes sense? – Shiva Nov 23 '18 at 05:53
  • @secretsuperstar No caution needed. You seem to keep missing the point: **the input data *is* in UTC**. If you wish to see the same moment in another time zone, apply a `ZoneId` to the `Instant` to get a `ZonedDateTime`. I and others have written this up on Stack Overflow many dozens if not hundreds of times already. Search for "site:stackoverflow.com java.time Instant ZoneId 8601 ZonedDateTime UTC" and ye shall receive. – Basil Bourque Nov 23 '18 at 06:11
  • In particular, I suggest: [*What's the difference between Instant and LocalDateTime?*](https://stackoverflow.com/q/32437550/642706) – Basil Bourque Nov 23 '18 at 06:14
  • Sure, I will do. Just wondering same format `SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");` is being used in accepted answer. so is this the case that zone information will not be ignored there but it is ignored in `LocalDateTime` – Shiva Nov 23 '18 at 06:22
  • I have edited my answer last one more question: `LocalDateTime.parse("1980-02-22T12:10:02Z", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneOffset.UTC))` would this also be correct answer, as I have added zone information to formatter? Thanks for your help! – Shiva Nov 23 '18 at 06:24
  • The single quotes around the `Z` means the fact of UTC will be ignored. – Basil Bourque Nov 23 '18 at 07:33