正如您已经猜到的那样,错误的根本原因是日期时间字符串的模式与您在DateTimeFormatter
. 如果您已经知道获取日期时间字符串的所有日期时间模式,则可以DateTimeFormatter
使用多个可选模式创建(通过将模式括在方括号中)。如果您收到未知模式的日期时间(即您没有放入的模式DateTimeFormatter
),您可以根据您的要求抛出异常或处理它。
我需要使用用户指定的语言环境和时区将任何传入的日期时间字符串解析为唯一的模式,以便稍后将其正确存储在数据库中:
此要求有两个部分:A.解析并将用户指定的语言环境和时区中的日期时间转换为等效的日期时间UTC
(不仅推荐,而且某些数据库也需要,例如PostgreSQL
)B.将其保存到数据库。
满足第一部分要求的步骤是:
- 由于接收到的日期时间在用户指定的时区,因此忽略日期时间字符串中包含的时区并将其解析为
LocalDateTime
.
- 在用户指定的时区转换为
LocalDateTime
。ZonedDateTime
- 将其转换
ZonedDateTime
为UTCZonedDateTime
。
- 最后,转换
ZonedDateTime
为OffsetDateTime
.
一旦你有了OffsetDateTime
,你可以将它存储到数据库中,如下所示:
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);// odt is the instance of OffsetDateTime
st.executeUpdate();
st.close();
您可以使用以下测试工具来测试需求的第一部分:
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// Test
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter the date-time string (press Enter without entering anything to quit): ");
String strDateTime = scanner.nextLine();
if (strDateTime.isBlank()) {
break;
}
boolean valid;
// Create Locale
Locale locale = null;
do {
valid = true;
System.out.print("Enter language code e.g. en, fr, in: ");
String languageTag = scanner.nextLine();
if (!isValidForLocale(languageTag)) {
System.out.println("Invalid code. Please try again.");
valid = false;
} else {
locale = Locale.forLanguageTag(languageTag);
}
} while (!valid);
// Create ZoneId
ZoneId zoneId = null;
do {
valid = true;
System.out.print("Enter timezone in the format Continent/City e.g. Asia/Calcutta: ");
String timezone = scanner.nextLine();
try {
zoneId = ZoneId.of(timezone);
} catch (Exception e) {
System.out.println("Invalid timezone. Please try again.");
valid = false;
}
} while (!valid);
try {
System.out.println(getDateTimeInUTC(strDateTime, locale, zoneId));
} catch (DateTimeParseException e) {
System.out.println("The date-time string has the following problem:\n" + e.getMessage());
System.out.println("Please try again.");
}
}
}
static OffsetDateTime getDateTimeInUTC(String strDateTime, Locale locale, ZoneId zoneId)
throws DateTimeParseException {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("[uuuu-M-d H:m:s][EEE MMM d H:m:s zzz uuuu]", locale);
// Ignore the timezone contained in strDateTime and parse strDateTime to
// LocalDateTime. Then, convert the LocalDateTime to ZonedDateTime at zoneId.
// Then, convert this ZonedDateTime to ZonedDateTime at UTC. Finally, convert
// the ZonedDateTime to OffsetDateTime and return the same.
ZonedDateTime zdt = LocalDateTime.parse(strDateTime, dtf).atZone(zoneId).withZoneSameInstant(ZoneOffset.UTC);
return zdt.toOffsetDateTime();
}
static boolean isValidForLocale(String languageTag) {
return Arrays.stream(Locale.getISOLanguages()).anyMatch(l -> Objects.equals(l, languageTag));
}
}
示例运行:
Enter the date-time string (press Enter without entering anything to quit): Mon Dec 21 21:18:37 GMT 2020
Enter language code e.g. en, fr, in: en
Enter timezone in the format Continent/City e.g. Asia/Calcutta: Asia/Calcutta
2020-12-21T15:48:37Z
Enter the date-time string (press Enter without entering anything to quit): 2020-1-23 5:15:8
Enter language code e.g. en, fr, in: en
Enter timezone in the format Continent/City e.g. Asia/Calcutta: Asia/Calcutta
2020-01-22T23:45:08Z
Enter the date-time string (press Enter without entering anything to quit):