从毫秒时间到Java日期转换

从毫秒时间到Java日期转换,java,date,calendar,Java,Date,Calendar,我试图计算从给定日期开始的偏移时间。我以字符串的形式获取日期并对其进行解析,得到了以毫秒为单位的偏移量。比如说 日期:2015-08-18 00:00:00 抵销时间:2678400000,应用于日期等于31天后的2015-09-18 00:00:00 我的目标是将每个偏移量(年/月/天/小时/分钟/秒)存储在一个数组中,以便以后使用。 但是,当我使用Calendar类运行此计算时,由于某些原因,当使用offsetConverter(2678400000)调用时,我会得到额外的小时数 这是我的代

我试图计算从给定日期开始的偏移时间。我以字符串的形式获取日期并对其进行解析,得到了以毫秒为单位的偏移量。比如说

日期:2015-08-18 00:00:00

抵销时间:2678400000,应用于日期等于31天后的2015-09-18 00:00:00

我的目标是将每个偏移量(年/月/天/小时/分钟/秒)存储在一个数组中,以便以后使用。 但是,当我使用Calendar类运行此计算时,由于某些原因,当使用offsetConverter(2678400000)调用时,我会得到额外的小时数

这是我的代码,我从这个链接中找到并稍加修改

公共静态int[]偏移转换器(长偏移){
int[]延迟=新的int[6];
//延迟0-3=年/月/天/秒
Calendar c=Calendar.getInstance();
c、 setTimeInMillis(偏移量);
延迟[0]=c.get(日历年)-1970年;
延迟[1]=c.get(日历月);
延迟[2]=c.get(日历日/月);
延迟[3]=c.get(日历小时);
延迟[4]=c.get(日历分钟);
延迟[5]=c.get(日历秒);
for(int i=0;i

如果有人看到我做错了什么,或者有一个更简单的方法来做这件事,我会感谢你的帮助。谢谢

Date#getTime()开始的毫秒到达UTC时区,但您使用默认时区实例化日历,默认时区是您的本地时区。这会给你的成绩增加额外的时间

要解决此问题,请使用UTC时区创建一个
日历
实例:

Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
tl;博士 2015-09-18T00:00

条款 这里的“偏移”一词是一个糟糕的术语选择。这个词在日期-时间处理中有一个特定的含义:时区与UTC之间的小时、分钟和秒数。有关详细信息,请参阅Wikipedia条目

你似乎关心的是与时间线无关的时间跨度。在java.time类中,如果以小时-分-秒为单位,这种跨度称为
持续时间
,如果以年-月-天为单位,则称为
期间

java.time 现代方法使用java.time类取代了麻烦的旧日期时间类,如
date
/
Calendar

持续时间
将时间跨度从毫秒计数转换为
持续时间
对象

Duration d = Duration.ofMillis( 2_678_400_000L );
这正好是744小时

d、 toString():PT744H

出于好奇,我检查了744小时内的天数,如果我们将“天”定义为24小时的大块

d、 今天的斯巴特():31

看来你真的打算一个月或31天。不管怎样,Java都有相应的类

如果你真的想:(31*24小时),那么一定要使用
持续时间。但是用更多的自文档化代码构建
Duration
对象

Duration d = Duration.ofDays( 31 ) ;  // Exact same effect as `Duration.ofMillis( 2_678_400_000L )` but more clear as to your intention.
ISO 8601 您的输入字符串几乎符合日期时间格式的ISO8601标准。在解析/生成字符串时,java.time类默认使用标准格式

将字符串转换为符合。用“<代码> t>代码>替换中间的空间。

String input = "2015-08-18 00:00:00".replace( " " , "T" ) ;
2015-08-18T00:00:00

LocalDateTime
将您的输入解析为,因为您的输入缺少或的指示符

ldt.toString():2015-08-18T00:00

添加您的
持续时间
对象以获得新的时间。time类使用,因此原始对象保持不变

LocalDateTime thirtyOneTimes24HoursLaterLdt = ldt.plus( d ) ;  // Adding a span-of-time to our `LocalDateTime` object to get another `LocalDateTime` object.
第三十一次24小时通话时间:2015-09-18T00:00

请注意,
LocalDateTime
并不表示实际时刻,即时间线上的特定点。如果不考虑时区或UTC的偏移量,则只能大致了解26-27小时范围内的潜在时刻

ZoneDateTime
如果您确实知道输入字符串表示特定区域中的某个时刻,请应用
ZoneId
以获取
ZonedDateTime
对象(实际时刻)

zdt.toString():2015-08-18T00:00+12:00[太平洋/奥克兰]

如果您不关心日期(日历上的整天),则可以添加
持续时间

第三十一次24小时的旅行时间:2015-09-18T00:00+12:00[太平洋/奥克兰]

如果您的业务逻辑实际上是指日历上的31天,请使用
期间

ZonedDateTime thirtyOneDaysLater = zdt.plus( Period.ofDays( 31 ) ) ;
thirtyOneDaysLater.toString():2015-09-18T00:00+12:00[太平洋/奥克兰]

如果您的业务逻辑实际上是计划一个日历月,而不是特定的天数,请使用不同的
期间。该课程根据需要进行调整,以处理不同月份的长度(并遵循)

月后。toString():2015-09-18T00:00+12:00[太平洋/奥克兰]


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

使用兼容的或更高版本,您可以直接与数据库交换java.time对象。不需要字符串,也不需要java.sql.*类

从哪里获得java.time类

  • ,及以后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类
    • 对于早期的Android,该项目采用了ThreeTen Backport(如上所述)。看
该项目使用其他类扩展了java.time。该项目是未来可能增加项目的试验场
String input = "2015-08-18 00:00:00".replace( " " , "T" ) ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;
LocalDateTime thirtyOneTimes24HoursLaterLdt = ldt.plus( d ) ;  // Adding a span-of-time to our `LocalDateTime` object to get another `LocalDateTime` object.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;  // Now we have determined an actual moment, a point on the timeline.
ZonedDateTime thirtyOneTimes24HoursLaterZdt = zdt.plus( d ) ;
ZonedDateTime thirtyOneDaysLater = zdt.plus( Period.ofDays( 31 ) ) ;
ZonedDateTime monthLater = zdt.plus( Period.ofMonths( 1 ) ) ;