如何仅更改 Java 中 Date 对象的时间而保留日期信息不变

How to change just the time of the Date object in Java leaving the date information intact

我有一个 Date 变量,可以说是 deliveryDate。它以这种格式保存在 MonngoDB 中。

ISODate("2020-10-07T03:10:00Z")

现在我想更改交货日期的时间属性。但它必须基于一些 String 来完成,它告诉要设置什么时间。例如 String time = "7:20 AM" [这个时间是马来西亚吉隆坡]。那么结果应该是这样的:

deliveryDate = ISODate("2020-10-07T11:20:00Z")

一些一般说明:7:20 星期一上午,在马来西亚吉隆坡联邦直辖区吉隆坡,11:20 星期日下午,协调世界时 (UTC)。

现在给出字符串时间和日期交货日期。我怎样才能获得所有情况下的上述结果?

我期待的是:

public static Date adjustTimeOfDay(Date deliveryDate, String timeOfDay) {
    // Adjust the time of the day of deliveryDate on the basis of timeOfDay 
    // Keep the offset and zone same while adjusting
    return deliveryDate
}

您可以使用兼容性方法 java.util.Date.toInstant(),操纵 Instant 的时间,这会创建一个不同的 Instant,然后通过以下方式转换回 Date Date.from(Instant instant).

这是一个操作示例方法:

public static Instant adjustTimeOfDay(Instant instant, String timeOfDay) {
    // convert the instant to an offset-aware datetime object
    OffsetDateTime deliveryOdt = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
    
    /*
     * provide a formatter that parses a time-of-day String.
     * PLEASE NOT that this formatter is not very lenient,
     * the String must be of the pattern "hh:mm a"
     */
    DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("hh")
            .appendLiteral(':')
            .appendPattern("mm")
            .appendLiteral(' ')
            .appendPattern("a")
            .parseCaseInsensitive()
            .toFormatter();
    
    // parse that String to a LocalTime
    LocalTime localTime = LocalTime.parse(timeOfDay, dtf);
    
    /*
     * create a new OffsetDateTime
     * adding the new LocalTime to the old LocalDate at UTC
     */
    OffsetDateTime adjustedOdt = OffsetDateTime.of(deliveryOdt.toLocalDate(),
                                                                localTime,
                                                                ZoneOffset.UTC);
    
    return adjustedOdt.toInstant();
}

我在 main 中这样使用:

public static void main(String[] args) {
    /*
     * instead of creating a Date,
     * I directly use Instant here and parse your example String,
     * so just use your deliveryDate.toInstant()
     */
    String input = "2020-10-07T03:10:00Z";
    Instant instant = Instant.parse(input);
    // then take a time of day to be set
    String timeOfDayUpdate = "07:20 AM";
    Instant adjusted = adjustTimeOfDay(instant, timeOfDayUpdate);
    System.out.println(input + " ==> " + OffsetDateTime.ofInstant(adjusted, ZoneOffset.UTC)
                                                        .format(DateTimeFormatter.ISO_INSTANT));
}

创建了以下输出:

2020-10-07T03:10:00Z ==> 2020-10-07T07:20:00Z

编辑

您可以将该方法重写为

public static Date adjustTimeOfDay(Date date, String timeOfDay) {
    // convert the date to an instant and the instant to an offset-aware datetime object
    OffsetDateTime deliveryOdt = OffsetDateTime.ofInstant(date.toInstant(), ZoneOffset.UTC);
    
    // provide a formatter that parses a time-of-day String 
    DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("hh")
            .appendLiteral(':')
            .appendPattern("mm")
            .appendLiteral(' ')
            .appendPattern("a")
            .parseCaseInsensitive()
            .toFormatter();
    
    // parse that String to a LocalTime
    LocalTime localTime = LocalTime.parse(timeOfDay, dtf);
    
    /*
     * create a new OffsetDateTime
     * adding the new LocalTime to the old LocalDate at UTC
     */
    OffsetDateTime adjustedOdt = OffsetDateTime.of(deliveryOdt.toLocalDate(),
            localTime,
            ZoneOffset.UTC);
    // return a Date from the Instant you get out of the OffsetDateTime
    return Date.from(adjustedOdt.toInstant());
}

传递 Date 并返回一个。

如果我正确理解了您的要求,您正在寻找类似的东西:

import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(adjustTimeOfDay("2020-10-07T03:10:00Z", "7:20 AM"));
    }

    public static String adjustTimeOfDay(String deliveryDate, String timeOfDay) {
        // Define the formatter to parse time like 7:20 AM
        DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder()
                                            .parseCaseInsensitive()
                                            .appendPattern("h:m a")
                                            .toFormatter(Locale.ENGLISH);

        return ZonedDateTime.parse(deliveryDate)
                .toLocalDate()
                .atTime(LocalTime.parse(timeOfDay, timeFormatter))
                .atZone(ZoneId.of("Asia/Kuala_Lumpur"))
                .withZoneSameInstant(ZoneOffset.UTC)
                .format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss")) + 'Z';

    }
}

输出:

2020-10-06T23:20:00Z

我建议您使用 HH 来表示 24 小时格式的时间。但是,如果你想通过忽略 AM/PM 来获得时间字符串,你可以在上面给出的模式中使用 hh 然后你会得到 2020-10-06T11:20:00Z (但我不推荐它,因为它任何人都会感到困惑)。