waz*_*zza 2 datetime jodatime java-8 java-time
如何在Java 8中实现以下功能java.time:
DateTime dt = new DateTime(year, month, date, hours, min, sec, milli);
Run Code Online (Sandbox Code Playgroud)
但我找到了这个选项:
OffsetDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond, offset)
Run Code Online (Sandbox Code Playgroud)
但它只有毫秒的方法.
我怎样才能达到与Joda-Time相同的效果?
小智 7
要将毫秒调整为纳秒,只需将毫秒值乘以1000000(100万).
但是,要获得正确的偏移量,这有点棘手.
DateTime当您没有指定时,Joda 使用系统的默认时区.所以,在java.time时候,很自然地认为这只是一个使用的物质ZoneId.systemDefault()(系统默认的时区),以获得该日期的有效偏移-这对大多数时间工作,但也有一些角落情况下,你必须知道.
时区可能在历史记录中有不同的偏移量 - 如今,大多数变化都是由夏令时(DST)引起的,但也可能因为某些政府/政府决定改变它而发生.
例如:在1985年,阿卡的巴西国家已经标准偏移UTC-05:00(和UTC-04:00DST期间),则在1988年它是在UTC-05:00 没有 DST,然后在2008年的标准改变为UTC-04:00(没有DST),并且自2013年起又回到UTC-05:00和无DST .
这可能听起来像一个极端的情况,但这样的变化可以随时随地发生.
所有这一切只是为了表明偏移取决于时区和日期.面对极端情况时,你必须做出一些决定.
对于这个例子,我将使用我的默认时区,这是America/Sao_Paulo(这里我们每年都有DST).目前,我们的偏移是-03:00,但在2017 年10月15 日午夜,时钟将向前移动1小时(从午夜到凌晨1点),并且偏移将更改为-02:00.
在这种情况下,午夜和凌晨1点之间的时段被"跳过",它们之间的任何本地时间都是无效的(这称为间隙).实际上,如果你试图在Joda-Time中创建这样的日期和时间,它会抛出异常:
// reminding that my system's default timezone is America/Sao_Paulo
DateTime d = new DateTime(2017, 10, 15, 0, 10, 0, 0);
Run Code Online (Sandbox Code Playgroud)
抛出:
org.joda.time.IllegalInstantException:非法瞬间由于时区偏移过渡(夏令时"间隙"):2017-10-15T00:10:00.000(美国/圣保罗)
但是java.time,在ZonedDateTime类中,它将其调整为下一个有效偏移量:
// reminding that my system's default timezone is America/Sao_Paulo
ZonedDateTime z = ZonedDateTime.of(2017, 10, 15, 0, 10, 0, 0, ZoneId.systemDefault());
Run Code Online (Sandbox Code Playgroud)
价值z是:
2017-10-15T01:10-02:00 [美国/圣保罗]
请注意,它将00:10调整为下一个有效偏移量(-02:00),并且时间也相应地调整为01:10.然后你可以这样做:
OffsetDateTime odt = z.toOffsetDateTime()
Run Code Online (Sandbox Code Playgroud)
得到你的OffsetDateTime(在这种情况下,价值将是2017-10-15T01:10-02:00).
当DST结束时,它也很复杂.在圣保罗,夏令时将于2018 年2月18 日结束.午夜,时钟将向后移动1小时(至2月17 日晚上11点),抵消将返回-03:00.
因此,2月17 日下午23点到2月18 日午夜之间的时间段将存在两次(首先是-02:00偏移,然后是-03:00偏移 - 这称为重叠).对于晚上11点到午夜之间的当地时间,将有2个有效的抵消,因此您必须决定使用哪个.
幸运的是,ZonedDateTime提供了2个选择:你可以使用withEarlierOffsetAtOverlap()DST更改之前得到补偿(在我的情况,它会-02:00),并withLaterOffsetAtOverlap()获得了DST更改后(在我的情况下,它会抵消-03:00):
// reminding that my system's default timezone is America/Sao_Paulo
z = ZonedDateTime.of(2018, 2, 17, 23, 30, 0, 0, ZoneId.systemDefault());
System.out.println(z.withEarlierOffsetAtOverlap()); // 2018-02-17T23:30-02:00[America/Sao_Paulo]
System.out.println(z.withLaterOffsetAtOverlap()); // 2018-02-17T23:30-03:00[America/Sao_Paulo]
Run Code Online (Sandbox Code Playgroud)
输出将是:
2018-02-17T23:30-02:00 [America/Sao_Paulo] 2018-02-17T23
:30-03:00 [America/Sao_Paulo]
注意方法如何在with...OffsetAtOverlapDST更改之前和之后获得偏移 - 还要注意本地时间23:30存在两次,在2个不同的偏移(-02:00和-03:00)中.一旦您选择使用哪一个,您可以致电toOffsetDateTime()获取您的OffsetDateTime实例:
OffsetDateTime beforeDSTChange = z.withEarlierOffsetAtOverlap().toOffsetDateTime();
OffsetDateTime afterDSTChange = z.withLaterOffsetAtOverlap().toOffsetDateTime();
Run Code Online (Sandbox Code Playgroud)
beforeDSTChange会2018-02-17T23:30-02:00和afterDSTChange会2018-02-17T23:30-03:00.
默认情况下,ZonedDateTime使用较早的偏移量创建日期/时间,但我相信最好通过调用相应的方法使其明确显示您正在使用的那个.并且在只有一个偏移有效的情况下,两个方法都返回相同的内容.
顺便说一下,我在Joda-Time 2.9.9中测试了这个相同的日期,它得到了更早的偏移量-02:00:
// reminding that my system's default timezone is America/Sao_Paulo
System.out.println(new DateTime(2018, 2, 17, 23, 30, 0, 0));
Run Code Online (Sandbox Code Playgroud)
2018-02-17T23:30:00.000-02:00
并且DateTime该类也有类似的方法withEarlierOffsetAtOverlap()和 withLaterOffsetAtOverlap()工作方式ZonedDateTime.
当然,大多数时候你可以ZonedDateTime毫无顾虑地使用- DST和任何其他偏移变化不会一直发生.但重要的是要注意这些角落情况并相应地进行调整.
另外一个警告:ZoneId.systemDefault()您可以通过使用来明确您想要的时区,而不是使用ZoneId.of("zonename").API使用IANA时区名称(始终采用格式Region/City,如America/Sao_Paulo或Europe/Berlin).避免使用3个字母的缩写(如CST或PST),因为它们不明确且不标准.
您可以通过调用获取可用时区列表(并选择最适合您系统的时区)ZoneId.getAvailableZoneIds().最好明确说明您正在使用的时区,因为系统的默认值可以在不事先通知的情况下进行更改,即使在运行时也是如此.
如果你有两个 Joda DateTime和java.time可用,你也可以从一个转换为另一个.
你可以从Joda获得epoch millis值DateTime来创建一个java.time.Instant.然后创建一个ZoneId具有相同ID DateTime区域的ID ,并获取相应的偏移量Instant并连接各个部分以创建OffsetDateTime:
DateTime d = new DateTime(2018, 2, 17, 23, 30, 0, 0);
// convert to java.time.Instant, using the same epoch millis value
Instant instant = Instant.ofEpochMilli(d.getMillis());
// get the offset for that instant, in the same zone of the Joda's DateTime instance
ZoneOffset offset = ZoneId.of(d.getZone().getID()).getRules().getOffset(instant);
// get the OffsetDateTime in the offset above
OffsetDateTime odt = instant.atOffset(offset); // 2018-02-17T23:30-02:00
Run Code Online (Sandbox Code Playgroud)
结果将是2018-02-17T23:30-02:00.请注意,DateTime对象使用较早的偏移量(如上所述),但d.withLaterOffsetAtOverlap().getMillis()如果要使用后面的偏移量,则可以选择使用.
提醒一下,在DST差距的情况下,如前所述,Joda-Time会抛出异常.
| 归档时间: |
|
| 查看次数: |
4501 次 |
| 最近记录: |