为什么AWST和CCT的时间不一样?

我写了一个名为“DateUtils”的静态类,这里是一个名为“parseDate(String)”的静态方法,它将使用一些模式将字符串转换为日期。 默认时区是亚洲/上海(我在中国)

public static final TimeZone SHA = TimeZone.getTimeZone("Asia/Shanghai");  

并将其传递给TimeZone.setDefault(timeZone)方法; 并使用SimpleDateFormat来协调字符串。 匹配的模式应该是“EEE,dd MMM yyyy HH:mm:ss zzz”以下是它的三个测试。

//this one is ok.
@Test
public void testParseGMTDate() throws Exception {
    Date date = DateUtils.parseDate("Thu, 02 Aug 2016 08:12:34 GMT");
    assertNotNull(date);
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    log.debug(DateUtils.format(cal.getTime()));
    assertEquals(cal.get(Calendar.YEAR), 2016);
    assertEquals(cal.get(Calendar.MONTH), 8 - 1);
    assertEquals(cal.get(Calendar.DATE), 2);
    assertEquals(cal.get(Calendar.HOUR_OF_DAY), 8 + 8);
    assertEquals(cal.get(Calendar.MINUTE), 12);
    assertEquals(cal.get(Calendar.SECOND), 34);
    assertEquals(DateUtils.format(cal.getTime()), "2016-08-02 16:12:34");
}
// AWST is GMS+8:00 time so this one is ok.
@Test 
public void testParseWSTDate() throws Exception {
    Date date = DateUtils.parseDate("Thu, 02 Aug 2016 08:12:34 AWST");
    assertNotNull(date);
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    log.debug(DateUtils.format(cal.getTime()));
    assertEquals(cal.get(Calendar.YEAR), 2016);
    assertEquals(cal.get(Calendar.MONTH), 8 - 1);
    assertEquals(cal.get(Calendar.DATE), 2);

    assertEquals(cal.get(Calendar.HOUR_OF_DAY), 8);
    assertEquals(cal.get(Calendar.MINUTE), 12);
    assertEquals(cal.get(Calendar.SECOND), 34);
}

// junit.framework.AssertionFailedError: 
// Expected :9
// Actual   :8
@Test
public void testParseDateCCT() throws Exception {
    Date date = DateUtils.parseDate("Thu, 02 Aug 2016 08:12:34 CCT");
    assertNotNull(date);
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    log.debug(DateUtils.format(cal.getTime()));
    assertEquals(cal.get(Calendar.YEAR), 2016);
    assertEquals(cal.get(Calendar.MONTH), 8 - 1);
    assertEquals(cal.get(Calendar.DATE), 2);

    assertEquals(cal.get(Calendar.HOUR_OF_DAY), 8); //Expected: 9
    assertEquals(cal.get(Calendar.MINUTE), 12);
    assertEquals(cal.get(Calendar.SECOND), 34);
}

这里有一些DateUtils的代码片段。

public static final TimeZone SHA = TimeZone.getTimeZone("Asia/Shanghai");
static {
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeZone(SHA);
    calendar.set(2000, 0, 1, 0, 0, 0);
    calendar.set(MILLISECOND, 0);
    TWO_DIGIT_START = calendar.getTime();

}
public static Date parseDate(String dateValue) {
    return parseDate(dateValue, null, null, SHA);
}
public static Date parseDate(String dateValue, String[] dateFormats, Date startDate, TimeZone timeZone) {
        TimeZone.setDefault(timeZone);
        String[] localDateFormats = dateFormats != null ? dateFormats : DEFAULT_PATTERNS;
        Date localStartDate = startDate != null ? startDate : TWO_DIGIT_START;
        String v = dateValue;
        if (dateValue.length() > 1 && dateValue.startsWith("'") && dateValue.endsWith("'")) {
            v = dateValue.substring(1, dateValue.length() - 1);
        }

        String[] arr = localDateFormats;
        int len = localDateFormats.length;

        for (String dateFormat : DEFAULT_PATTERNS) {
            //            String dateFormat = arr[i];
            SimpleDateFormat dateParser = DateUtils.DateFormatHolder.formatFor(dateFormat);
            dateParser.set2DigitYearStart(localStartDate);
            ParsePosition pos = new ParsePosition(0);
            Date result = dateParser.parse(v, pos);
            if (pos.getIndex() != 0) {
                _LOG.debug("Date parsed using: {}", dateFormat);
                return result;
            }
        }

        _LOG.error("Can't parse data: {data:{}, formats:{}, startDate:{},tz:{}}",
                dateValue, localDateFormats, localStartDate, TimeZone.getDefault());
        return null;
    }

我的问题是:根据互联网上的文件,CCT&AWST都是GMT + 8时区,为什么在我的测试中,CCT时间似乎是GMT + 9:00。


TL;博士

你犯了三个错误:

  • 使用非标准非独特伪时区3-4字母缩写
  • 然后继续错误地假定他们的意思
  • 使用旧的过时Java类进行日期时间处理。
  • 相反,请使用continent/region格式的适当时区名称。 研究这些区域的记录意义,而不是假设/猜测。 日期时间工作只使用java.time类。

    所有这些都是很多程序员犯的常见错误,Stack Overflow上的许多问题都证明了这一点。

    使用适当的时区名称

    CST也是北美洲的Central Standard Time 。 为什么你不应该使用这些3-4个字母缩写的一个例子。 它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。 使用适当的IANA时区名称。 这些格式为continent/region

    java.time

    你正在使用旧的麻烦日期时间课程。 避免它们。

    java.time框架内置于Java 8及更高版本中。 这些类取代了旧的麻烦日期时间类,如java.util.Date.Calendarjava.text.SimpleDateFormat 。 Joda-Time团队还建议迁移到java.time。

    要了解更多信息,请参阅Oracle教程。 并搜索堆栈溢出了很多例子和解释。

    大部分java.time功能都在ThreeTen-Backport中移植到Java 6和7,并在ThreeTenABP中进一步适用于Android。

    Instant

    Instant类是UTC(GMT)时间轴上的一个时刻,分辨率高达纳秒。

    Instant instant = Instant.parse ( "2016-08-02T08:12:34Z" ); // 02 Aug 2016 08:12:34
    

    ZonedDateTime

    ZonedDateTime表示Instant调整为时区。

    我认为你的意思是澳大利亚西部标准时间AWST ,官方名为Australia/Perth

    ZoneId zoneId_Perth = ZoneId.of ( "Australia/Perth" );
    ZonedDateTime zdt_Perth = instant.atZone ( zoneId_Perth );
    

    对于中国,你打算Asia/Shanghai

    ZoneId zoneId_Shanghai = ZoneId.of ( "Asia/Shanghai" );
    ZonedDateTime zdt_Shanghai = zdt_Perth.withZoneSameInstant ( zoneId_Shanghai );
    

    我不确定你的或旧的日期时间课程由CCT意味着什么。 此页面显示它是“科科斯群岛时间”,比UTC全年提前六个半小时(无夏令时,夏令时)。 再次,这是为什么你不应该使用3-4字母缩写的例子。

    ZoneId zoneId_Cocos = ZoneId.of ( "Indian/Cocos" );
    ZonedDateTime zdt_Cocos = zdt_Perth.withZoneSameInstant ( zoneId_Cocos );
    

    根据评论,你可能意味着北京时间。 如果是这样,请根据维基百科的这个列表了解北京时间是由Asia/Shanghai时区覆盖的。

    转储到控制台。 你可以看到,珀斯和上海在今年16:12:3408:12:34提前了8个小时,每天16个小时对8个小时( 16:12:3408:12:34 )。 科科斯群岛位于UTC时间之前的14:42:34 ,时间为6.5小时。

    System.out.println ( "instant: " + instant + " | zdt_Perth: " + zdt_Perth + " | zdt_Shanghai: " + zdt_Shanghai + " | zdt_Cocos: " + zdt_Cocos );
    

    即时:2016-08-02T08:12:34Z | zdt_Perth:2016-08-02T16:12:34 + 08:00 [Australia / Perth] | zdt_上海:2016-08-02T16:12:34 + 08:00 [亚洲/上海] | zdt_Cocos:2016-08-02T14:42:34 + 06:30 [印度/科科斯]

    DateTimeFormatter

    要以不同于此处显示的标准ISO 8601格式的格式生成字符串,请使用DateTimeFormatter类。

    DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL );
    f = f.withLocale( Locale.CHINA );
    String output = zdt_Shanghai.format( f );
    
    链接地址: http://www.djcxy.com/p/951.html

    上一篇: Why the time of AWST and CCT are not the same?

    下一篇: Print using Java a date and time from a MySql DATETIME field