如何在时区更改时为DateTime添加时间?

时间:2015-05-22 12:23:11

标签: java datetime time timezone dst

我有以下代码来为DateTime实例添加时间:

set "path=D:\Build"
set "config=x86"
set "type=Release"
set "fileName=abc.dll"



set "filePath=%path%\%config%\%type%\%fileName%"

if exist filePath (
:copy file code)

这将创建一组10次添加到arraylist。但是,当添加6小时时,有一个夏令时的变化。由于时区变化,如何在添加/删除额外小时时生成正确的时间?目前它不会使用此方法删除/添加额外的小时。

例如,如果我要在2015年10月24日上午10:00开始运行代码,我希望生成以下时间。请注意,时区在2015年10月25日凌晨02:00更改。

  options = {
        karma: {
            unit: {
                options: {
                    files: ['test/unit/specs/*.js'],
                    reporters: ['progress', 'coverage'],
                    preprocessors: {
                        'src/js/*.js': ['coverage']
                    },
                    coverageReporter: {
                        type : 'html',
                        dir : 'build/coverage/'
                    },
                    frameworks: ['jasmine'],
                    singleRun: true
                }
            }
        }
}

2 个答案:

答案 0 :(得分:2)

通常我会给Jon Skeet留下正确的答案(他的最后评论在我看来或多或少是一个答案),但是现在有两个其他不可接受的答案错过了关键点。

您的问题"可以缩小到这些界限和(错误的)期望:

  

24/10/2015 22:00:00 BST

     

25/10/2015 05:00:00 GMT

你正确地写道,在2015-10-25凌晨2点,英国的夏令时重新开始回到冬季。这意味着标有" 01"发生两次(重叠情况),因为时钟被设置回来并重复这个小时。因此,作为时钟位置的标称小时数必须增加一小时以获得以小时为单位的实际物理持续时间。在数学上:

nominal duration + one hour = real duration (= 6 real hours)
=> nominal duration = (6 - 1) hours = 5 virtual hours

请记住,时间戳如" 24/10/2015 22:00:00 BST" (在ISO偏移表示法中:" 2015-10-24T22:00:00 + 01")代表全局物理瞬间,因此这些瞬间之间的时间差表示物理持续时间。原始时刻的持续时间为6小时包含一小时,但是您必须从实际时间中删除一小时以获得名义持续时间(以时钟位置 - 见上面给定方程式的第二部分)。因此,即时表示法:

[2015-10-24T22:00+01] + 6 physical hours = 
  [2015-10-25T04:00+01] = [2015-10-25T03:00+00] = [2015-10-25T03:00Z]

在标称的本地时间戳记表示法中(只是观察时钟位置):

[2015-10-24T22:00] + 5 virtual hours (clock positions) = [2015-10-25T03:00]

因此,重复一个时钟位置可以减少标称持续时间,但不会增加它。

这就是Joda-Time正确的做法:

DateTime d1 = new DateTime(2015, 10, 24, 10, 0, 0, 0, DateTimeZone.forID("Europe/London"));

for (int x = 1; x <= 10; x++) {
    d1 = d1.plusHours(6);
    System.out.println("> " + d1.toString());
}

> 2015-10-24T16:00:00.000+01:00
> 2015-10-24T22:00:00.000+01:00
> 2015-10-25T03:00:00.000Z
> 2015-10-25T09:00:00.000Z
> 2015-10-25T15:00:00.000Z
> 2015-10-25T21:00:00.000Z
> 2015-10-26T03:00:00.000Z
> 2015-10-26T09:00:00.000Z
> 2015-10-26T15:00:00.000Z
> 2015-10-26T21:00:00.000Z

答案 1 :(得分:0)

别担心,请使用java.time

  • 显然你正在使用Joda-Time库。请改用java.time。
  • java.time类自动处理夏令时(DST)切换。
  • 除了可能影响您感兴趣的时区的tzdata time zone database更改以使JVM保持最新状态外,您无需执行任何操作。请参阅Oracle’s provided tool for tzdata个更新。

java.time

让我们看一下使用java.time类添加六个小时的结果。

定义日期和时间部分。

LocalDate ld = LocalDate.of ( 2015, Month.OCTOBER, 24 );  // 24th Oct 2015 at 10:00am per the Question.
LocalTime lt = LocalTime.of ( 10, 0 );

Europe/London定义ZoneId对象的时区。

ZoneId z = ZoneId.of ( "Europe/London" );

组合以创建ZonedDateTime对象。

ZonedDateTime zdtStart = ZonedDateTime.of ( ld, lt, z );

Instant中提取ZonedDateTimeInstant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

Instant instantStart = zdtStart.toInstant ( );

将我们的时间跨度定义为6小时Duration。 java.time类可以通过添加Duration对象来执行日期时间数学运算。

Duration未附加到时间轴,实际上存储了若干秒和几纳秒。因此,在这个课程中没有关于“六小时”以及时钟和DST等的智能。当我们要求Duration六小时时,该班级立即计算(每小时6小时* 60分钟*每分钟60秒)=总共21,600秒。

Duration sixHours = Duration.ofHours ( 6 );  // 21,600 seconds = ( 6 hours * 60 minutes per hour * 60 seconds per minute ).

循环十次。首先将Duration添加到ZonedDateTime,然后将结果转换为Instant

// Increment the `ZonedDateTime`.
ZonedDateTime zdt = zdtStart;
for ( int i = 1 ; i <= 10 ; i++ ) {
    System.out.println ( ">zdt.toString() " + zdt + " | zdt.toInstant().toString(): " + zdt.toInstant ( ) + "\n");
    // Set up next loop.
    zdt = zdt.plus ( sixHours );
}

运行时。请注意伦敦时间的时间跳跃。这是Daylight Saving Time (DST)转换,秋天的“后退”时间,当英格兰切换回标准时间时,从+01:00的偏移量到+00:00的祖鲁偏移量,凌晨2点,时钟跳回,重复凌晨1点。因此,我们原本预计在凌晨4点22:00加6小时后,我们会看到凌晨3点。您可以在Instant值中看到确实已经过了六个小时。诀窍在于,伦敦人在一个小时左右的时间内将钟表收回。

请参阅history of DST cutoversEurope/London

  

zdt.toString()2015-10-24T10:00 + 01:00 [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-24T09:00:00Z

     

zdt.toString()2015-10-24T16:00 + 01:00 [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-24T15:00:00Z

     

zdt.toString()2015-10-24T22:00 + 01:00 [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-24T21:00:00Z

     

zdt.toString()2015-10-25T03:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-25T03:00:00Z

     

zdt.toString()2015-10-25T09:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-25T09:00:00Z

     

zdt.toString()2015-10-25T15:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-25T15:00:00Z

     

zdt.toString()2015-10-25T21:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-25T21:00:00Z

     

zdt.toString()2015-10-26T03:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-26T03:00:00Z

     

zdt.toString()2015-10-26T09:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-26T09:00:00Z

     

zdt.toString()2015-10-26T15:00Z [欧洲/伦敦] | zdt.toInstant()。toString():2015-10-26T15:00:00Z

为了好玩,我们互换,连续六小时添加到Instant并将结果转换为伦敦时间。

// Increment the `Instant`.
Instant instant = instantStart;
for ( int i = 1 ; i <= 10 ; i++ ) {
    System.out.println ( ">instant.toString() " + instant + " | instant.atZone(z).toString(): " + instant.atZone ( z ) + "\n");
    // Set up next loop.
    instant = instant.plus ( sixHours );
}

运行时,我们会看到相同的值输出。

  

instant.toString()2015-10-24T09:00:00Z | instant.atZone(z).toString():2015-10-24T10:00 + 01:00 [欧洲/伦敦]

     

instant.toString()2015-10-24T15:00:00Z | instant.atZone(z).toString():2015-10-24T16:00 + 01:00 [欧洲/伦敦]

     

instant.toString()2015-10-24T21:00:00Z | instant.atZone(z).toString():2015-10-24T22:00 + 01:00 [欧洲/伦敦]

     

instant.toString()2015-10-25T03:00:00Z | instant.atZone(z).toString():2015-10-25T03:00Z [欧洲/伦敦]

     

instant.toString()2015-10-25T09:00:00Z | instant.atZone(z).toString():2015-10-25T09:00Z [欧洲/伦敦]

     

instant.toString()2015-10-25T15:00:00Z | instant.atZone(z).toString():2015-10-25T15:00Z [欧洲/伦敦]

     

instant.toString()2015-10-25T21:00:00Z | instant.atZone(z).toString():2015-10-25T21:00Z [欧洲/伦敦]

     

instant.toString()2015-10-26T03:00:00Z | instant.atZone(z).toString():2015-10-26T03:00Z [欧洲/伦敦]

     

instant.toString()2015-10-26T09:00:00Z | instant.atZone(z).toString():2015-10-26T09:00Z [欧洲/伦敦]

     

instant.toString()2015-10-26T15:00:00Z | instant.atZone(z).toString():2015-10-26T15:00Z [欧洲/伦敦]

请参阅此code run live at IdeOne.com

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore