1

I have received a string in format "yyyy-MM-dd'T'HH:mm:ssXXX"

e.g. "2020-06-01T11:04:02+02:00"

I want to convert it into "yyyy-MM-dd'T'HH:mm:ss:SSSZ"

e.g "2020-06-01T11:04:02.000+0200"

I don't know the time zone actually. It should take from that last part of string as it is.

I have tried but it is taking my local time and time zone when I convert string to date(i.e IST).

        SimpleDateFormat sd1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        //sd1.setTimeZone(TimeZone.getTimeZone("PST"));
        Date dt = sd1.parse("2020-06-01T11:04:02+02:00");
        SimpleDateFormat sd2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss:SSSZ");
        System.out.println(sd2.format(dt));

Output:

2020-06-01T14:34:02:000+0530

Only date is right, time and timezone has changed.

I know I am doing it wrong, it will be really helpful if someone can tell me how can I do this. Thanks for the help.

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Akshay Gaikwad
  • 141
  • 1
  • 8
  • [Date Time](https://docs.oracle.com/javase/tutorial/datetime/index.html) tutorial – Abra Jun 05 '20 at 17:33
  • 1
    Does this answer your question? [SimpleDateFormat parse loses timezone](https://stackoverflow.com/questions/18122608/simpledateformat-parse-loses-timezone) – rph Jun 05 '20 at 17:34
  • Why are you using `Date` and `SimpleDateFormat`? Java 8 has the `java.time` with much improved alternatives. – fjsv Jun 05 '20 at 17:35
  • @rph no that question did not help me – Akshay Gaikwad Jun 05 '20 at 18:07
  • @fjsventura I haven't worked much in java. Can you please elaborate how that can help me in this conversion. – Akshay Gaikwad Jun 05 '20 at 18:09
  • 1
    [1] The _"+02:00"_ within your call to `sd1.parse("2020-06-01T11:04:02+02:00")` is incorrect, but is ignored rather than treated as invalid. The Javadoc for `parse()` states _"The method **may not use the entire text** of the given string"_, and a time zone value is meaningless for a `Date`. Verify this by changing it some other value (such as _"+09:00"_) and see that it has no effect. [2] Please update your question to clarify the **exact** output you want/expect for some sample input. – skomisa Jun 06 '20 at 06:05

3 Answers3

14

Table of all date-time types in Java, both modern and legacy

OffsetDateTime

You said:

I have received a string in format "yyyy-MM-dd'T'HH:mm:ssXXX"

e.g. "2020-06-01T11:04:02+02:00"

No need to define a formatting pattern. Your input complies with the ISO 8601 standard.

These standard formats are used by default in the java.time classes when parsing/generating strings.

Your input should be parsed as a OffsetDateTime.

String input = "2020-06-01T11:04:02+02:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input ) ;

odt.toString(): 2020-06-01T11:04:02+02:00

Offset-from-UTC versus time zone

You said:

I don't know the time zone actually.

That +02:00 on the end is not a time zone. That text represents a mere offset-from-UTC. An offset is just a number of hours-minutes-seconds, positive or negative. A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region. A time zone has a name in the format of Continent/Region, such as Europe/Brussels or Africa/Cairo.

You can adjust from a mere offset to a specific time zone. Apply a ZoneId to get a ZonedDateTime.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; 
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

zdt.toString(): 2020-06-01T14:34:02+05:30[Asia/Kolkata]

You said:

It should take from that last part of string as it is.

I am not sure what you meant by that. If you parse your input as an OffsetDateTime, that object knows its offset, accessible as a ZoneOffset.

ZoneOffset offset = odt.getOffset() ;

See the code shown in this Answer run live at IdeOne.com.

offset.toString(): +02:00

Formatting strings

You said:

I want to convert it into "yyyy-MM-dd'T'HH:mm:ss:SSSZ"

e.g "2020-06-01T11:04:02.000+0200"

Not sure what you mean here. Do you mean to force the display of milliseconds even if the value is zero? Firstly, you should know that java.time objects have a resolution of nanoseconds for up to nine decimal digits, much finer that the milliseconds shown in 3 digits of a decimal fraction. Secondly, forcing display of fractional second has been covered on Stack Overflow, such as here. Always search Stack Overflow before posting.

Or do you mean displaying the offset without a COLON character as a delimiter between minutes and seconds?

  • I advise against this. While dropping the COLON is technically allowed by the ISO 8601 standard, I have seen more than one software library or system fail to handle an offset without that delimiter. Ditto for using an offset of hours without the minutes. I advise always using the hours, the minutes, and the delimiter.
  • If you insist, use DateTimeFormatter with a formatting pattern. Study the Javadoc, keeping mind that the formatting codes are (a) case-sensitive, and (b) sensitive to repeating the character 0, 1, or more times. Here we use xx to get the hours and minutes of an offset without the COLON character delimiting. (Again, I do not recommend that format.)

Code shown in that same IdeOne.com page.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSxx" ) ;     
String output = odt.format( f ) ;

output: 2020-06-01T11:04:02.000+0200

Date::toString injects time zone

You said:

I have tried but it is taking my local time and time zone when I convert string to date(i.e IST).

The java.util.Date::toString method tells a lie. While well-intentioned, that method unfortunately applies the JVM’s current default time zone to the Date value as it generates the text. The Date class actually represents a moment in UTC. This is one of many reasons to never use Date. That class nowadays is replaced by java.time.Instant.


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.

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

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

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. Hibernate 5 & JPA 2.2 support java.time.

Where to obtain the java.time classes?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • 2
    Yeah, actually I was confused between time zone and zone offset, ZoneOffset did the work. thank you so much for your answer and clarification. – Akshay Gaikwad Jun 08 '20 at 16:40
5

The first suggestion I would make to you is to switch from using the Date object to LocalDateTime (java 8+)

Using the new API would work in this way

String YOUR_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YOUR_DATE_TIME_PATTERN);
LocalDateTime dateTime = LocalDateTime.parse(input_date, formatter);

//Then you can set your timezone in this way - remember to replace the values with the proper timezone you want. 



ZonedDateTime zonedUTC = dateTime.atZone(ZoneId.of("UTC"));

ZonedDateTime zonedIST = zonedUTC.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));

let me know if that works for you

  • It is giving me **2020-06-01T11:04:02** output and I want that +0200 (see example in question), actually date-time can came from various timezones, is there any way we can identify that. Thanks. – Akshay Gaikwad Jun 05 '20 at 18:14
  • Can you use some regex or string parsing to extract the timezone you need? – Daniel Vilas-Boas Jun 06 '20 at 04:08
  • Switching to java.time is a very good idea. `LocalDateTime` is the wrong class to use, you are losing the offset information from the stirng. `ZonedDateTime` will work, but `OffsetDateTime` is a still better fit. – Ole V.V. Jun 06 '20 at 10:49
2

To elaborate the comment and picking up on @Daniel Vilas-Boas answer, you should go for Java8 and I think what you want is something like:

public static void main(String[] args) {
    String YOUR_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
    String YOUR_NEW_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss:SSSZ";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YOUR_DATE_TIME_PATTERN);
    DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern(YOUR_NEW_DATE_TIME_PATTERN);
    ZonedDateTime zonedDateTime = ZonedDateTime.parse("2020-06-01T11:04:02+02:00", formatter);

    ZoneId from = ZoneId.from(zonedDateTime);
    System.out.println(from);

    ZonedDateTime zonedIST = zonedDateTime.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));

    System.out.println(zonedDateTime.format(newFormatter));
    System.out.println(zonedIST.format(newFormatter));
}

The prints should print:

2020-06-01T11:04:02:000+0000
2020-06-01T16:34:02:000+0530

EDIT

Included ZoneId to allow handling different timezones.

fjsv
  • 705
  • 10
  • 23
  • Thank you for your answer. Just one more thing. Is there any way form that we can identify the time zone my date have? like in above example it's +02:00, I want that +02:00 in output but in next input it might be +05:30 or something else how can we solve that. hope you understand what I want to say. – Akshay Gaikwad Jun 05 '20 at 18:42
  • I've updated my code to include what you requested. The `from` will return the ZoneId (in this case just `+02:00`) and you can use it to handle different zones – fjsv Jun 05 '20 at 19:05
  • 1
    Thank you for your help, because I did not knew the actual time zone, with ZoneOffset I extracted that offset from string itself. – Akshay Gaikwad Jun 08 '20 at 16:42