首页 > 解决方案 > 考虑本地时区,在java中将日期转换为纪元秒

问题描述

我想将日期转换为纪元范围(当天上午 12 点,当天格林威治标准时间晚上 11.59)。

  1. fromDate=2019-10-25T00:00:00-07:00, toDate=2019-10-25T23:59:59-07:00: 想返回 (1571986800,1572073199) (相当于GMT 10月25日的时间戳, 2019 年上午 7:00:00,格林威治标准时间 2019 年 10 月 26 日上午 6:59:59)
  2. fromDate=2019-10-24T00:00:00-07:00, toDate=2019-10-24T23:59:59-07:00: 想返回 (1571900400,1571986799) (相当于GMT 10月24日的时间戳, 2019 年上午 7:00:00,格林威治标准时间 2019 年 10 月 25 日上午 6:59:59)

我的尝试:

fromDate = String.valueOf(formatter.parse(fromDate.substring(0, 19)).toInstant().getEpochSecond());
toDate = String.valueOf(formatter.parse(toDate.substring(0, 19)).toInstant().getEpochSecond());
epochDateRange.append("(").append(fromDate).append(",").append(toDate).append(")");

通过设置为其他时区进行调试时:即在eclipse中添加以下参数-调试配置

'-Duser.timezone=Asia/Kuala_Lumpur'
  1. 对于上述时区,它在 10 月 25 日返回 (1571932800,1572019199) 但想要的结果是 (1571986800,1572073199)

  2. 对于上述时区,在 Oct24 它返回 (1571846400,1571932799) 但想要的结果是 (1571900400,1571986799)

任何帮助将不胜感激。谢谢。

标签: javatimezoneepoch

解决方案


你的问题很混乱。所以我只能猜测你想要做什么。但主要问题可能是您误解了什么是从纪元开始计数。

一方面,常用的时代参考日期时间有几十个。总是说出你的意思。与 Java 捆绑在一起的日期时间类使用 1970 年 UTC 的第一刻,即 1970-01-01T00:00Z。

另一方面,您可能没有意识到 count-from-epoch 必须引用偏移量或时区才有意义。同样,在 Java 中,我们使用上面提到的 UTC,并且在上面看到Z的字符串的末尾可以看到,采用标准ISO 8601格式。

另一个问题是,您似乎试图通过确定一天的最后一刻来代表一整天的开始和结束。这是有问题的。在日期时间处理中,我们通常使用半开方法来定义时间跨度。在半开中,开头是包容的,而结尾是排斥的。因此,一天从第一刻开始,一直持续到但不包括第二天的第一刻。

OffsetDateTime start = OffsetDateTime.parse( "2019-10-25T00:00:00-07:00" );
OffsetDateTime stop = start.plusDays( 1 ) ;

start.toString(): 2019-10-25T00:00-07:00

stop.toString(): 2019-10-26T00:00-07:00

另一个问题是使用12:00:00 AM. 这可能是表示午夜滚动的一种棘手方式。我建议坚持使用 24 时钟进行编码。因此,UTC 中的一天总是从 00:00:00.0 开始。(顺便说一句,在某些日期的某些时区,这一天并不总是从 00:00 开始。

另一个问题是您使用偏移量而不是时区。例如,如果您知道时区是 ,请America/Phoenix使用该时区而不是-07:00.

至于你从-07:00 的偏移量跳到格林威治标准时间,你把我弄丢了。我不明白你的意思。但也许这会有所帮助。

如果您想查看 2019-10-25T00:00:00-07:00 的 UTC 时间,只需InstantOffsetDateTime. 根据定义, AnInstant始终采用 UTC。

OffsetDateTime
.parse( "2019-10-25T00:00:00-07:00" )
.toInstant()
.toString() 

2019-10-25T07:00:00Z

因此,您调用 2019-10-25T00:00:00-07:00 相当于 2019 年 10 月 25 日 12:00:00 AM GMT(实际上,GMT 和 UTC 是相同的)是荒谬的。第-07:00一个字符串上的表示日期时间比 UTC 晚七个小时。因此,UTC 中具有相同时间的同一日期不可能代表同一时刻。

也许您的目标是获得某个地区(某个时区)的人们所看到的一天中的第一刻。

ZoneId z = ZoneId.of( "Asia/Kuala_Lumpur" ) ;
LocalDate ld = LocalDate.parse( "2019-10-25" ) ;
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
ZonedDateTime zdtStop = zdtStart.plusDays( 1 ) ;

当调整为 UTC 时,请查看启动和停止。

Instant utcStart = zdtStart.toInstant() ;
Instant utcStop = zdtStop.toInstant() ;

以整秒为粒度获取从 1970-01-01T00:00:00Z 开始的计数。

long secondsSinceEpochStart = utcStart.getEpochSecond() ;
long secondsSinceEpochStop = utcStop.getEpochSecond() ;

zdtStart/zdtStop: 2019-10-25T00:00+08:00[Asia/Kuala_Lumpur]/2019-10-26T00:00+08:00[Asia/Kuala_Lumpur]

utcStart/utcStop: 2019-10-24T16:00:00Z/2019-10-25T16:00:00Z

secondsSinceEpochStart/secondsSinceEpochStop: 1571932800/1572019200

查看所有这些代码在 IdeOne.com 上实时运行。你可以在那里轻松地进行分叉和实验。

顺便说一句,如果您在跟踪一对时刻的时间跨度上做了大量工作,请将ThreeTen-Extra库添加到您的项目中以访问该类Interval。此类表示一对Instant对象,以及许多有用的方法,例如abutscontains等。

ZonedDateTime start = LocalDate.of( 2019, Month.OCTOBER , 25 ).atStartOfDay( ZoneOffset.UTC ) ;
Interval dayInUtc = Interval.of( 
    start.toInstant() ,
    start.plusDays( 1 ).toInstant() 
) ;
String epochCounts = dayInUtc.getStart().getEpochSecond() + "/" + dayInUtc.getEnd().getEpochSecond() ;

…并且在一个时区:

ZonedDateTime start = LocalDate.of( 2019, Month.OCTOBER , 25 ).atStartOfDay( ZoneId.of( "Asia/Kuala_Lumpur" ) ) ;
Interval dayInKualaLumpur = Interval.of( 
    start.toInstant() ,
    start.plusDays( 1 ).toInstant() 
) ;
String epochCounts = dayInKualaLumpur.getStart().getEpochSecond() + "/" + dayInKualaLumpur.getEnd().getEpochSecond() ;

推荐阅读