如何解决如何使用 T 和 Z 将 LocalDate 格式化为 ISO 8601?
我正在尝试生成随机日期和时间,并将其转换为 "yyyy-MM-dd'T'HH:mm:ss'Z'"
格式。
这是我尝试过的:
public static String generaterandomDateAndTimeInString() {
LocalDate date = LocalDate.Now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
System.out.println("date and time :: " + date.toString());
return formatDate(date) ;
}
public static String formatDate(LocalDate date){
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
return dateFormat.format(date);
}
但在行 dateFormat.format(date)
中,它抱怨:
java.lang.IllegalArgumentException:无法将给定的对象格式化为日期
第二个问题是,print的输出不包含时间:
date :: 1998-12-24
我不知道如何让它工作。
解决方法
切勿使用 java.time
格式化 SimpleDateFormat
类型
使用 SimpleDateFormat
,您应该只格式化旧的日期时间类型,例如java.util.Date
。为了格式化 java.time
日期时间类型,您需要使用 DateTimeFormatter
。
切勿将 Z
括在单引号内
以某种格式将 Z
括在单引号内是一个错误。符号 Z
代表 zulu
并指定 UTC+00:00
。如果将其括在单引号中,则它仅表示字符文字 Z
,并且在解析时不会起到 UTC+00:00
的作用。
您不需要明确使用格式化程序
对于此要求,您不需要显式使用格式化程序,因为 OffsetDateTime#toString
已经以您需要的格式返回字符串。但是,如果 OffsetDateTime
对象中的 秒 数为零,则相同的和后续更小的单位将被 OffsetDateTime#toString
截断。如果您需要完整格式而不考虑 seconds 的值,那么您当然必须使用 DateTimeFormatter
。
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Random;
public class Main {
public static void main(String[] args) {
System.out.println(generateRandomDateAndTimeInString());
}
public static String generateRandomDateAndTimeInString() {
LocalDate date = LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
System.out.println("date and time :: " + date.toString());
return formatDate(date);
}
public static String formatDate(LocalDate date) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX");
// return date.atStartOfDay().atOffset(ZoneOffset.UTC).toString();
return date.atStartOfDay().atOffset(ZoneOffset.UTC).format(dtf);
}
}
示例运行:
date and time :: 1996-09-05
1996-09-05T00:00:00Z
请注意,java.util
的日期时间 API 及其格式 API SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern date-time API。
- 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7。
- 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。
从 Trail: Date Time 了解有关现代日期时间 API 的更多信息。
如果您出于任何原因仍需要使用 SimpleDateFormat
:
使用LocalDate
将ZonedDateTime
转换为ZoneOffset.UTC
,并在一天开始时➡️将ZonedDateTime
转换为Instant
➡️从中获取java.util.Date
对象Instant
。
public static String formatDate(LocalDate date) {
Date utilDate = Date.from(date.atStartOfDay(ZoneOffset.UTC).toInstant());
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
return dateFormat.format(utilDate);
}
,
如果你想忽略时间部分,那么你可以像这样使用 ZonedDateTime
:
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
return ZonedDateTime.of(
date,LocalTime.MIN,ZoneId.of("Europe/Paris")
).format(dateFormat);
输出示例
2013-10-19T00:00:00+0200
或者更好的是,您可以仅使用 toString
将格式化日期作为默认格式为 ZonedDateTime
的字符串获取:
return ZonedDateTime.of(
date,ZoneId.of("Europe/Paris")
).toString();
输出
2013-10-19T00:00+02:00[Europe/Paris]
注意
这个日期总是用 00:00:00
表示时间部分,因为我们使用的是 LocalTime.MIN
此外,您可以将 ZoneId
更改为预期的 Zone
,这只是一个示例。
重要
DateFormat
和 SimpleDateFormat
是遗留库,因此请不要将它们与 java.time
库混合使用,在顶部您使用的是 LocalDate
,这意味着您正在使用这个 java.time
库,所以请在所有代码中继续使用它。
ZoneOffset utc = ZoneOffset.UTC;
LocalDate today = LocalDate.now(utc);
LocalDate seventyYearsAgo = today.minusYears(70);
int totalDays = Math.toIntExact(ChronoUnit.DAYS.between(seventyYearsAgo,today));
LocalDate date = today.minusDays(new Random().nextInt(totalDays));
String dateString = date.atStartOfDay(utc).toString();
System.out.println("date and time :: " + dateString);
示例输出:
日期和时间 :: 1983-08-24T00:00Z
注意事项:
- 让 java.time 从年转换为天。它提供了更具可读性和更正确的代码(一年并不总是 365 天)。
- 要在字符串中包含时间和 UTC 偏移量,请转换
ZonedDateTime
或OffsetDateTime
,因为此类对象包含时间和偏移量。LocalDate
没有。这是一个没有时间的日期,也没有与 UTC 的偏移量。您要求的Z
表示与 UTC 的偏移量为 0。
如果您也想要输出中的小时、分钟和秒,您可以通过计算秒而不是天来实现。在这种情况下,对整个操作使用 OffsetDateTime
(如果在与 UTC 不同的时区,则使用 ZonedDateTime
)。
ZoneOffset utc = ZoneOffset.UTC;
OffsetDateTime today = OffsetDateTime.now(utc).truncatedTo(ChronoUnit.SECONDS);
OffsetDateTime seventyYearsAgo = today.minusYears(70);
long totalSeconds = ChronoUnit.SECONDS.between(seventyYearsAgo,today);
OffsetDateTime date = today.minusSeconds(ThreadLocalRandom.current().nextLong(0,totalSeconds));
String dateString = date.toString();
System.out.println("date and time :: " + dateString);
日期和时间:: 1996-09-21T06:49:56Z
我使用 ThreadLocalRandom
是因为它可以在指定的时间间隔内生成一个随机长值。有趣的是,ThreadLocalRandom
有很多 Random
没有的方便方法。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。