0

I have a date string that looks like this:

"2018-04-12T21:25:28.0000000-0700"

I need to convert this to a Date object but it needs to apply the -7 offset so that the time is

2:25:28 pm 

instead of

9:25:28 pm

is there an easy way to do this?

I tried:

String dateString = "2018-04-12T21:25:28.0000000-0700";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date date = sdf.parse(dateString);

but I get:

date = 12/04/2018 9:25:28 PM

not 
date = 12/04/2018 2:25:28 PM

Thanks so much for the help!

Jeremy P
  • 1,309
  • 2
  • 13
  • 22
  • 3
    That `-0700` (better formatted as -07:00) means the time-of-day and date shown represent a moment seven hours behind UTC, such as seen in `America/Los_Angeles` time zone. So subtracting seven hours makes no sense at all. If you want to see the same moment as UTC, *add* seven hours, not subtract. – Basil Bourque Apr 13 '18 at 00:17
  • As an aside consider throwing away the long outmoded and notoriously troublesome `SimpleDateFormat` and friends, and adding [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) to your Android project in order to use `java.time`, the modern Java date and time API. It is so much nicer to work with. – Ole V.V. Apr 13 '18 at 08:26

4 Answers4

1

As mentioned in a comment by Basil Bourque, you need to add 7 hours to get UTC/GMT time, not subtract 7 hours. The shown offset is the offset already applied to the time, not the offset to apply to get UTC time. Read it as "at offset -7 hours".

Using Java 8 Time API, you do it like this:

String dateString = "2018-04-12T21:25:28.0000000-0700";

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSSSSSZ");
LocalDateTime dateTime = OffsetDateTime.parse(dateString, fmt)
                                       .atZoneSameInstant(ZoneOffset.UTC)
                                       .toLocalDateTime();

System.out.println(dateTime.format(DateTimeFormatter.ofPattern("uuuu-MM-dd hh:mm:ss a")));

Output

2018-04-13 04:25:28 AM

Andreas
  • 154,647
  • 11
  • 152
  • 247
1

java.time

You are using terribly troublesome old date-time classes that were supplanted years ago by the java.time classes.

Define a formatting pattern to match your input.

String input = "2018-04-12T21:25:28.0000000-0700";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSSSSSX"  );

Parse as an OffsetDateTime given that your input has an offset-from-UTC but not a time zone.

OffsetDateTime odt = OffsetDateTime.parse( input , formatter );

odt.toString(): 2018-04-12T21:25:28-07:00

Understand offset-from-UTC

You asked “to apply the -7 offset”. You may be misunderstanding the meaning of the ISO 8601 format used by your input string. That "minus seven" offset of -0700 (better formatted with a colon as -07:00) means the date and time shown represent a moment seven hours behind UTC. This offset is used by several time zones such as America/Los_Angeles . There is no need to apply anything, as the offset is already "applied". This string means 9 PM in the evening on the 12th of April 2018 on the west coast of North America.

Perhaps what you really want is the same moment seen as UTC. In that case, you need to add seven hours, not subtract. Do not read a ISO 8601 string as an equation. A negative number means behind UTC, so add the same number of hours-minutes to get to UTC.

Furthermore, you need not do any math at all. For a UTC value, extract a Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = odt.toInstant() ;

instant.toString(): 2018-04-13T04:25:28Z

The Z on the end of an ISO 8601 string is short for Zulu and means UTC. so we can see that 4 AM on the following day in UTC happens at the very same time as 9 PM on the west coast of North America. In other words, 9 PM in Los Angeles is simultaneously 4 AM on the following date in Iceland and the Azores and in other places with an offset-from-UTC of zero hours.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

It looks like you haven't set a TimeZone to the SimpleDateFormat. I would advise to set GMT as the TimeZone -

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

This should return you the expected value : Thu Apr 12 14:25:28 PDT 2018

Ameya Pandilwar
  • 2,638
  • 28
  • 28
  • FYI, the 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 Apr 13 '18 at 00:15
  • Your given formatting pattern does not fit the data seen in the Question. – Basil Bourque Apr 13 '18 at 00:47
  • `Thu Apr 12 14:25:28 PDT 2018` is not the correct result. And yes, your code gave that result when I ran it, so it’s incorrect. – Ole V.V. Apr 14 '18 at 04:35
-1

Parse your date string into two strings thr date and the offset then subtract the offset from the date.

Turan
  • 302
  • 2
  • 9