java - java.util.Date 到 java.util.Calendar 奇怪的时区变化
问题描述
我想将 java.util.Date 对象设置为 java.util.Calendar 对象以更改 Date 对象的年份,如下所示:
TimezoneId 等于“Europe/Istanbul”。年份是 2018。
日期对象是 1969-12-31 22:00:00 .0 (1969-12-31T22:00:00.000Z),zoneinfo 如下:
“sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]"
欧洲/伊斯坦布尔时区是 UTC+3,但是当我使用此日期对象运行代码时,新的 GregorianCalendar 将日期对象的时间更改为 -1 小时。出现问题,我找不到为什么不将 UTC 转换为 UTC+3。返回日期对象等于 UTC 2017 年 12 月 31 日星期日 21:00: 00。UTC -1 对于欧洲/伊斯坦布尔不正确。我该如何解决这个问题?
public static Date setYearOfDate(Date date, int year, String timeZoneId)
{
Calendar customCalendar = new GregorianCalendar(TimeZone.getTimeZone(timeZoneId));
customCalendar.setTime(date);
customCalendar.set(Calendar.YEAR, year);
return customCalendar.getTime();
}
注意:customCalendar zoneinfo 如下: “sun.util.calendar.ZoneInfo[id="Europe/Istanbul",offset=10800000,dstSavings=0,useDaylight=false,transitions=130,lastRule=null]"
解决方案
java.time
我建议你使用java.time API 来做。
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
class Main {
public static void main(String[] args) {
String dateTimeString = "1969-12-31T22:00:00.000Z";
System.out.println(setYearOfDate(dateTimeString, 2018, "Europe/Istanbul"));
}
public static String setYearOfDate(String dateTimeString, int year, String zoneId) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH)
.withZone(ZoneId.of(zoneId));
ZonedDateTime zdt = ZonedDateTime.parse(dateTimeString);
zdt = zdt.withYear(year);
return dtf.format(zdt);
}
}
输出:
2019-01-01T01:00:00.000+03
java.util
日期时间 API 及其格式化 API已SimpleDateFormat
过时且容易出错。建议完全停止使用它们并切换到现代日期时间 API。
- 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。
- 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请通过 desugaring和How to use ThreeTenABP in Android Project检查Java 8+ APIs available。
错误行为的SimpleDateFormat
一个很好的例子如下所示:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
class Main {
public static void main(String[] args) throws ParseException {
String dateTimeString = "1969-12-31T22:00:00.000Z";
String timeZoneId = "Europe/Istanbul";
System.out.println(setYearOfDate(dateTimeString, 2018, timeZoneId));
}
public static String setYearOfDate(String dateTimeString, int year, String timeZoneId) throws ParseException {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH);
calendar.setTime(sdf.parse(dateTimeString));
calendar.set(Calendar.YEAR, year);
sdf.setTimeZone(TimeZone.getTimeZone(timeZoneId));
return sdf.format(calendar.getTime());
}
}
输出:
2019-01-01T02:00:00.000+03
您将在 1968 年和 1970 年观察到这种行为SimpleDateFormat
。但是,如果您将输入字符串中的年份更改为其他年份,它会以预期的方式运行,例如将为2019-01-01T01:00:00.000+03
输入字符串输出相同的代码,1979-12-31T22:00:00.000Z
.
推荐阅读
- java - 检索特定 id 上的特定记录信息
- javascript - 通过在 iFrame 中单击的按钮在新选项卡中打开链接
- mongodb - 无法通过 shell 登录 Mongo
- spring - Kubernetes 中的 Spring Boot (Tomcat) 服务需要使用 FQDN
- keras - LSTM - 使用 word2vec 完成句子
- javascript - 饼图在 PartialView 中不起作用
- javascript - 如何在 mongoose 中将此数组传递给回调 'meme.find({}, (err, meme) => { const memes = meme.map(m => m); });'
- sql - RODBC sqlQuery 与 sqlFetch
- android - KeyStore Provider 中不需要加密的密钥是什么?
- python - 从教程复制的代码的“语法错误:无效语法”用于 tensorflow 急切执行