简体   繁体   中英

How to format Date string to date and time using ZonedDateTime?

I have string like "2021-06-01" and i wish to convert it to the "2021-06-01T00:00:00+02:00" . I know that, the easiest solution is concatanation of string:

date = date+"T00:00:00+02:00";

However, i wish to do it using ZonedDateTime . Currently my solution is:

  public static String formatDate(String date, DateTimeFormatter formatter) {
    return ZonedDateTime.parse(date).format(formatter);
  }

and then call this method with:

formatDate('2021-06-01', DateTimeFormatter.ISO_LOCAL_DATE);

However, it complains with:

java.time.format.DateTimeParseException: Text '2021-06-01' could not be parsed at index 10

Any solution?

LocalDate#atStartOfDay

However, i wish to do it using ZonedDateTime.

It is similar (not exact) to your other question .

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(getOffsetDateTime("2021-06-01"));
    }

    public static OffsetDateTime getOffsetDateTime(String strDate) {
        return LocalDate.parse(strDate)
                .atStartOfDay(ZoneOffset.of("+02:00"))
                .toOffsetDateTime();
    }
}

Output:

2021-06-01T00:00+02:00

ONLINE DEMO

If seconds and fraction-of-second are zero, they omitted by default (ie from OffsetDateTime#toString ). If you want to retain them, you can use DateTimeFormatter eg

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(getOffsetDateTime("2021-06-01"));
        System.out.println(getFormattedOffsetDateTime(getOffsetDateTime("2021-06-01")));
    }

    public static OffsetDateTime getOffsetDateTime(String strDate) {
        return LocalDate.parse(strDate)
                .atStartOfDay(ZoneOffset.of("+02:00"))
                .toOffsetDateTime();
    }

    public static String getFormattedOffsetDateTime(OffsetDateTime odt) {
        return DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH).format(odt);
    }
}

Output:

2021-06-01T00:00+02:00
2021-06-01T00:00:00+02:00

ONLINE DEMO

Learn more about the modern Date-Time API from Trail: Date Time .

Your date string does not have a time, and does not have a zone, so it can't be parsed to a ZonedDateTime . You are also using the wrong DateTimeFormatter to format it. ISO_LOCAL_DATE produces the format yyyy-MM-dd , not the one you want.

You should instead parse the date string to a LocalDate , which is just a date , because there's only that much information in that string.

Then, you should add the time component and the offset component to the parsed date, then format it:

public static String formatDate(String date) {
    return LocalDate.parse(date)
        .atStartOfDay() // sets the time to 00:00:00
        .atOffset(ZoneOffset.ofHours(2)) // sets the offset to +02:00
        .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); // formats it using the desired format
}

Note that atOffset gives you an OffsetDateTime , which is enough for what you want to do. If you really want to use ZonedDateTime , just change it to atZone , and it will work too, but I think it's unnecessary.

If you want to always have an offset of +02:00 hours, a ZonedDateTime will not be a good choice because it will consider daylight saving time.

Here's a demo that shows why you might want to use an OffsetDateTime :

Assume you have two methods:

public static String formatDate(String date, int offset) {
    return LocalDate.parse(date)
                    .atStartOfDay(ZoneOffset.ofHours(offset))
                    .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}

and

public static String formatDate(String date, String zone) {
    return LocalDate.parse(date)
                    .atStartOfDay(ZoneId.of(zone))
                    .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}

Both of them take a String just like your example "2021-06-01" . The second argument is an offset in the first method and a zone name in the second.

Using both methods with the same date as String but different second arguments, like this

public static void main(String[] args) {
    String dateOne = "2021-06-11";
    String dateTwo = "2019-11-19";
    String dateThree = "1998-03-27";
    
    String zone = "Europe/Paris";
    int offsetHours = 2;
    
    System.out.println(formatDate(dateOne, offsetHours));
    System.out.println(formatDate(dateOne, zone));
    System.out.println(formatDate(dateTwo, offsetHours));
    System.out.println(formatDate(dateTwo, zone));
    System.out.println(formatDate(dateThree, offsetHours));
    System.out.println(formatDate(dateThree, zone));
}

will produce this output

2021-06-11T00:00:00+02:00
2021-06-11T00:00:00+02:00
2019-11-19T00:00:00+02:00
2019-11-19T00:00:00+01:00
1998-03-27T00:00:00+02:00
1998-03-27T00:00:00+01:00

As you can see, there are differences due to daylight saving time.
That means your requirement it should always be 02:00 given in a comment below your question will not reliably met if you use a ZonedDateTime (in a way it should be used).

Please note that both example methods use a DateTimeFormatter.ISO_OFFSET_DATE_TIME which produces a String in your desired format. You can safely use it with a ZonedDateTime while you cannot do it the other way round, that would mean formatting an OffsetDateTime with a DateTimeFormatter.ISO_ZONED_DATE_TIME because an OffsetDateTime does not have information about a zone. A ZonedDateTime does and, thus, always has information about the (zone-specific) offset.

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