简体   繁体   中英

Java 8 convert Date String into Date with timezone

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

eg "2020-06-01T11:04:02+02:00"

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

eg "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(ie 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.

Java 中所有日期时间类型的表,包括现代和传统

OffsetDateTime

You said:

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

eg "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"

eg "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(ie 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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM