Java 了解SimpleTimeZone和DST测试

Java 了解SimpleTimeZone和DST测试,java,calendar,timezone,dst,Java,Calendar,Timezone,Dst,我对在Java中使用SimpleTimeZone类有一个问题。首先,JavaDoc很好,但在开始和结束规则方面不太容易理解。但是在网络上找到的一些例子的帮助下,我成功地把它弄对了(我仍然不明白为什么8代表一个月中的第二周!!!但是无论如何) 现在,我编写了一个简单的Junit测试来验证我的理解: package test; import static org.junit.Assert.assertEquals; import java.sql.Timestamp; import java.u

我对在Java中使用SimpleTimeZone类有一个问题。首先,JavaDoc很好,但在开始和结束规则方面不太容易理解。但是在网络上找到的一些例子的帮助下,我成功地把它弄对了(我仍然不明白为什么8代表一个月中的第二周!!!但是无论如何)

现在,我编写了一个简单的Junit测试来验证我的理解:

package test;

import static org.junit.Assert.assertEquals;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;

import org.apache.log4j.Logger;
import org.junit.Test;



public class SimpleTimeZoneTest {

Logger log = Logger.getLogger(SimpleTimeZoneTest.class);

@Test   
public void testTimeZoneWithDST() throws Exception {


    Calendar testDateEndOut = new GregorianCalendar(2012, Calendar.NOVEMBER, 4, 01, 59, 59);
    Calendar testDateEndIn = new GregorianCalendar(2012, Calendar.NOVEMBER, 4, 02, 00, 00);
    Calendar testDateStartOut = new GregorianCalendar(2012, Calendar.MARCH, 11, 01, 59, 59);
    Calendar testDateStartIn = new GregorianCalendar(2012, Calendar.MARCH, 11, 02, 00, 00);

    SimpleTimeZone est = new SimpleTimeZone(-5 * 60 * 60 * 1000, "EST");
    est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);
    est.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);

    Calendar theCal = new GregorianCalendar(est);

    theCal.setTimeInMillis(testDateEndOut.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("End date Should be In DST", true, theCal.getTimeZone().inDaylightTime(theCal.getTime()));

    theCal.setTimeInMillis(testDateEndIn.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("End date Should be Out DST", false, theCal.getTimeZone().inDaylightTime(theCal.getTime()));

    theCal.setTimeInMillis(testDateStartIn.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("Start date Should be in DST", true, theCal.getTimeZone().inDaylightTime(theCal.getTime()));

    theCal.setTimeInMillis(testDateStartOut.getTimeInMillis());

    log.info(" Cal date = " + new Timestamp(theCal.getTimeInMillis()) + " : " + theCal.getTimeZone().getDisplayName());
    log.info(" Cal use DST = " + theCal.getTimeZone().useDaylightTime());
    log.info(" Cal In DST = " + theCal.getTimeZone().inDaylightTime(theCal.getTime()));
    log.info("offset = " + theCal.getTimeZone().getOffset(theCal.getTimeInMillis()));
    log.info("DTS offset= " + theCal.getTimeZone().getDSTSavings());
    assertEquals("Start date Should be Out DST", false, theCal.getTimeZone().inDaylightTime(theCal.getTime()));





}
}

好的,我想测试日期限制,看看inDaylightTime是否返回正确的内容

因此,我的规则是:

DST于3月的第二个星期日凌晨2点开始 DST在11月的第一个星期日凌晨2点结束

2012年(现在)这给了我们3月11日凌晨2点和11月4日凌晨2点的时间

你可以看到我的测试日期设置正确

这是我的测试结果:

2012-11-01 18:22:44,344 INFO [test.SimpleTimeZoneTest] - < Cal date = 2012-11-04 01:59:59.0 : Eastern Standard Time>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - < Cal use DST = true>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - < Cal In DST = false>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - <offset = -18000000>
2012-11-01 18:22:44,345 INFO [test.SimpleTimeZoneTest] - <DTS offset= 3600000>
为什么8意味着三月的第二周。。。还有周日。在一个真实的日历示例中,我无法理解这件事


谢谢

我还没有检查所有其他内容,但最直接的第一个问题是您正在默认时区中创建所有
日历
值。。。这意味着当你写作时:

theCal.setTimeInMillis(testDateEndOut.getTimeInMillis());
。。。这已经应用到你的系统默认时区

我强烈建议您完全摆脱
theCal
,并将代码更改为:

SimpleTimeZone est = new SimpleTimeZone(-5 * 60 * 60 * 1000, "EST");
est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);
est.setEndRule(Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);

Calendar testDateEndOut = new GregorianCalendar(est);
testDateEndOut.set(2012, Calendar.NOVEMBER, 4, 01, 59, 59);
Calendar testDateEndIn = new GregorianCalendar(est);
testDateEndIn.set(2012, Calendar.NOVEMBER, 4, 02, 00, 00);
Calendar testDateStartOut = new GregorianCalendar(est);
testDateStartOut.set(2012, Calendar.MARCH, 11, 01, 59, 59);
Calendar testDateStartIn = new GregorianCalendar(est);
testDateStartIn.set(2012, Calendar.MARCH, 11, 02, 00, 00);
这可能无法解决问题,但至少会让人们更容易对问题进行推理

或者,您可以使用UTC日历,并使用DST转换周围的UTC瞬间来测试您的时区

除此之外,我强烈建议您在所有日期/时间工作中使用而不是
java.util.*
。这是一个更好的API——尽管的文档也可能有点棘手

我的第一个断言失败了,告诉我2012-11-04 01:59:59不是inDST

11月4日凌晨2:00,我们“后退”到凌晨1:00,因此1:59:59发生两次,一次在DST内,一次在DST后;因此,这项声明:

Calendar testDateEndOut =
    new GregorianCalendar(2012, Calendar.NOVEMBER, 4, 01, 59, 59);
真的是模棱两可。恰巧,JDK决定它指的是第二次出现的1:59:59,也就是DST之外的那个,这就是为什么您看到这个结果

编辑为添加:您可以通过最初将
testDateEndOut
设置为00:00:00,然后写入
testDateEndOut.setTimeInMillis(testDateEndOut.getTimeInMillis()+7199000L)
将其向前移动所需的量,来消除这种歧义,并确保第一次出现

哦,顺便说一句,如果有人能详细说明一下:

est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);
est.setStartRule(Calendar.MARCH, 8, -Calendar.SUNDAY, 2 * 60 * 60 * 1000);
为什么8意味着三月的第二周。。。还有周日

java.util.SimpleTimeZone
支持许多不同的情况,因此它使用了一些魔力。您正在使用,因此您的参数如下所示:

  • startMonth
    -您已经理解了这一点<代码>三月表示三月
  • startDay
    -注意:天,而不是周<代码>8表示当月的第八天
  • startDayOfWeek
    -使用负值表示您希望在上述指定日期当天或之后有一天<代码>-星期日表示星期日当天或之后
  • startTime
    -您理解这一点

总之,
(Calendar.MARCH,8,-Calendar.SUNDAY,2*60*60*1000)
表示3月8日当天或之后的第一个星期日凌晨2:00,即3月的第二个星期日[3月8日,3月14日]。

我假设他的默认时区是东部时间;他试图验证自己创建一个规则复制东部时间的
SimpleTimeZone
的能力。带有
testDateEndOut
等的初始内容故意在默认时区中,因此他可以以毫秒为单位获得适当的时间戳,用于验证他的
SimpleTimeZone
实例。(你明白我的意思吗?)。基本上,我从GMT格式的外部xml中读取了两个时间戳,一个是beginDate,一个是endDate。我需要简单地转换这些日期在我的本地时区(EST)与DST铭记。我没有在Joda上读到任何能帮我解决这个问题的东西。。但我会试试看。再次感谢您的回复。@Cygnusx1:这绝对可以做到-您应该使用UTC将数据解析为
DateTime
值,然后使用
DateTime.withZone(yourZone)
将其转换。谢谢您的回答。你确认我对1小时差距的看法。。。3月8日对周日。我明白你告诉我的。。但我的逻辑会促使我写日历。星期天,而不是日历。星期天。对我来说-标志告诉我从3月8日开始往回走。。。但那只是我…-)@天鹅座1:不客气!是的,争论很复杂,很难记住。我认为对于不同类型的星期日选择算法,应该有不同的方法。虽然从另一方面来说,这不是一种经常被调用的方法,所以也许这并不重要?