Java:从日历实例开始的时间不对?

Java:从日历实例开始的时间不对?,java,calendar,Java,Calendar,运行: public class test { @Test public void displayDate() { SimpleDateFormat MONTH_FORMAT = new SimpleDateFormat("MMM", Locale.getDefault()); String testDateStr = "2017-07-01T07:58:23.000Z"; Calendar calendar = getFormat

运行:

public class test {
    @Test
    public void displayDate() {
        SimpleDateFormat MONTH_FORMAT = new SimpleDateFormat("MMM", Locale.getDefault());
        String testDateStr = "2017-07-01T07:58:23.000Z";
        Calendar calendar = getFormatedDate(testDateStr);
        int yearInt  = calendar.get(Calendar.YEAR);
        String monthStr = MONTH_FORMAT.format(calendar.getTime()).toUpperCase();
        int monthInt = calendar.get(Calendar.MONTH);
        int dayInt  = calendar.get(Calendar.DAY_OF_MONTH);
        int hour24 = calendar.get(Calendar.HOUR_OF_DAY);
        int min = calendar.get(Calendar.MINUTE);
        int sec = calendar.get(Calendar.SECOND);
        System.out.println(testDateStr);
        System.out.println(String.format("%s-%s-%s %s:%s:%s", yearInt, monthStr, dayInt, hour24, min, sec));
        System.out.println(String.format("%s-%s-%s %s:%s:%s", yearInt, monthInt, dayInt, hour24, min, sec));

    }

    private Calendar getFormatedDate(String dateStr) {
        Instant instant;
        try {
            instant = Instant.parse(dateStr);
        } catch (DateTimeParseException e) {
            e.printStackTrace();
            return null;
        }
        ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
        Calendar calendar = GregorianCalendar.from(zdt);
        return calendar;
    }
}
我得到:

2017-07-01T07:58:23.000Z
2017-JUL-1 9:58:23
2017-6-1 9:58:23
注意,我得到的小时数为9,而预期为7

问题

  • 为什么会有这样的结果
  • 如何得到正确的结果
  • 谢谢

    为什么会有这样的结果

    由于这一行:
    ZoneDateTime zdt=ZoneDateTime.ofInstant(instant,ZoneId.systemDefault())
    您正在将您的时区强加于
    日期str
    中定义的时区,因此日历将使用您的时区而不是原始时区

    如何得到正确的结果

    getFormattedDate
    方法更改为:

    private Calendar getFormatedDate(final String dateStr) {
        final ZonedDateTime zdt = ZonedDateTime.parse(dateStr);
        return GregorianCalendar.from(zdt);
    }
    

    为什么你认为这是错误的结果?您的默认时区可能比UTC早10小时,也可能比UTC晚2小时,对吗?区域偏移量是
    000Z
    ,因此不需要偏移,因为您可以使用现代日期时间类(
    Instant
    zoneDateTime
    ZoneId
    ,都来自java.time),我建议您专门使用java.time,并从代码中删除设计糟糕、现已过时的
    SimpleDataFormat
    Calendar
    GregoriaCalendar
    。它将使您的代码更简单、更清晰。java.time拥有您所需要的所有功能和更多功能。请澄清:
    .000
    是秒的几分之一(如果您愿意,可以是0毫秒)
    Z
    是区域偏移(无偏移,正确)。是否需要为7月份打印6的
    monthInt
    ?七月是第七个月,所以我觉得很困惑。谢谢你的解释。它起作用了。有分数的回答和投票!如果询问者真的(如真的、真的)需要
    日历
    对象(通常用于他们无法升级的遗留API),那么这个答案是正确的。通常情况下,人们不会使用
    ZonedDateTime
    来解析带有
    Z
    偏移量的字符串,但由于我们需要一个来生成
    日历
    ,因此在这种特殊情况下,这似乎是正确的方法。