首页 > 解决方案 > 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]"

标签: javadatetimezonesimpledateformatjava-time

解决方案


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

错误行为的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.


推荐阅读