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.

6
  • Date Time tutorial Commented Jun 5, 2020 at 17:33
  • 1
    Does this answer your question? SimpleDateFormat parse loses timezone Commented Jun 5, 2020 at 17:34
  • Why are you using Date and SimpleDateFormat? Java 8 has the java.time with much improved alternatives. Commented Jun 5, 2020 at 17:35
  • @rph no that question did not help me Commented Jun 5, 2020 at 18:07
  • 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. Commented Jun 6, 2020 at 6:05

3 Answers 3

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?

Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, actually I was confused between time zone and zone offset, ZoneOffset did the work. thank you so much for your answer and clarification.
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

3 Comments

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.
Can you use some regex or string parsing to extract the timezone you need?
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.
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.

3 Comments

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.
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
Thank you for your help, because I did not knew the actual time zone, with ZoneOffset I extracted that offset from string itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.