如何根据仅时间输入更改日期并考虑时区和夏令时?

How to change a Date based on time-only input and account for time zone and DST?

我需要根据用户提供的两个字符串创建一个新的 Java Date:一个日期(例如“1.1.2015”)和一个时间(例如“23 :00").首先,用户输入日期,该日期被发送到服务器并解析为 Date(一天中的时间设置为用户所在时区的午夜)。此后,用户输入发送到服务器的时间,需要创建一个新的 Date,将第一个 Date 实例的日期和新的时间结合起来用户输入。

示例:假设服务器的时区是UTC,而用户的时区是UTC-2。用户在日期字段中输入“1.1.2015”,在服务器中将其解释为 2:00 1.1.2015 UTC(UTC 时间 1 月 1 日 2:00 AM,这是用户时间的午夜区)。然后用户在时间字段(24 小时制)中输入“23:00”。这需要在服务器中解释为 1:00 2.1.2015 UTC(1 月 2 日 1:00 AM)。

我们使用 Apache Commons FastDateFormat 将字符串转换为 Dates,反之亦然,并使用 Joda Time 进行日期操作。结果需要是一个普通的旧 Java 日期。我试图将现有的 Date 实例和用户输入的时间结合起来,如下所示:

Date datePart= ...; // The date parsed from the first user input
FastDateFormat timeFormat = ...;
DateTimeZone userTimeZone = DateTimeZone.forTimeZone(timeFormat.getTimeZone());
String userTimeInput = ...; // The time of day from the user

MutableDateTime dateTime = new MutableDateTime(datePart, DateTimeZone.UTC);
Date newTime = timeFormat.parse(userTimeInput);
dateTime.setTime(new DateTime(newTime, DateTimeZone.UTC));

// Determine if the date part needs to be changed due to time zone adjustment
long timeZoneOffset = userTimeZone.getOffset(dateTime);
long newMillisOfDay = dateTime.getMillisOfDay();
if (newMillisOfDay + timeZoneOffset > 24 * 60 * 60 * 1000) {
    dateTime.addDays(-1);
} else if (newMillisOfDay + timeZoneOffset < 0) {
    dateTime.addDays(1);
}

Date newServerDate = dateTime.toDate();

像这样更改现有 Date 的时间有点问题。以上不起作用;如果用户多次更改一天中的时间,则可能每次都进行 +/-1 天调整。另外,上面的代码没有考虑夏令时。如果 datePart 是 DST,我们的示例用户输入的时间应该被视为 UTC-1。当使用 FastDateFormat 并且只解析一天中的时间时,日期被设置为纪元,这意味着用户输入的时间将始终被视为 UTC-2 时间。这将导致结果偏移一小时。

如何根据一天中的给定时间调整服务器中的Date并正确考虑时区和夏令时?

我使用 Jon 在评论中的建议解决了这个问题。我仍然必须以 Date 结束,所以我无法开始使用 Joda Time 处理所有事情。但是,对于这个特定的用例,我确实放弃了 FastDateFormat 和 MutableDateTime。感谢您的提示!解决方案如下所示:

Date datePart= ...;           // The date parsed from the first user input
String userTimeInput = ...;   // The time of day from the user
Locale userLocale = ...;
DateTimeZone userTimeZone = ...;

DateTime dateInUserTimeZone = new DateTime(datePart, userTimeZone);
DateTimeFormatter formatter = DateTimeFormat.shortTime().withLocale(userLocale);
LocalTime time = formatter.parseLocalTime(userTimeInput);

Date newDate = dateInUserTimeZone.withTime(time.getHourOfDay(), time.getMinuteOfHour(),
        time.getSecondOfMinute(), time.getMillisOfSecond()).toDate();