如何在Java / Scala中将时间戳(以微秒为单位)转换为日期。 我的目标是比较两个时间戳并找出它们之间的差异。 我正在使用java 8和示例Timestamp字符串是1474457086337977。 我想将其转换为Date或Timestamp实例。
答案 0 :(得分:6)
Instant.EPOCH.plus(
Duration.ofNanos(
TimeUnit.MICROSECONDS.toNanos(
Long.parse( "1474457086337977" ) ) ) )
java.time类支持nanoseconds的解决方案,对您的microseconds来说已经足够了。
将字符串解析为long
以获得纪元的微秒数。
long micros = Long.parse( "1474457086337977" );
当然,你总是可以使用整数文字。请注意L
附加到整数文字。
long micros = 1_474_457_086_337_977L ;
Instant
我们希望将UTC(1970-01-01T00:00:00Z
)中1970年初的epoch的微秒数转换为Instant
。 Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds。这意味着最多九位小数。
Instant
类有一个方便的静态方法,可以从count of whole seconds,count of whole seconds plus a fractional second in nanoseconds或count of milliseconds进行转换。但遗憾的是没有这样的方法可以计算微秒或纳秒。
作为一种解决方法,我们可以定义Duration
并将其添加到已定义为常量的纪元参考日期。我们可以将Duration
实例化为几纳秒。要获得纳秒,我们将您的微秒乘以一千。请注意使用64位long
而不是32位int
。
Duration duration = Duration.ofNanos( micros * 1_000L );
Instant instant = Instant.EPOCH.plus( duration );
instant.toString():2016-09-21T11:24:46.337977Z
或者,您可以使用TimeUnit
枚举将微秒转换为纳秒,而无需硬编码“幻数”。
Duration duration = Duration.ofNanos( TimeUnit.MICROSECONDS.toNanos( micros ) );
要调整到其他偏移或时区,请在StackOverflow中搜索Java类OffsetDateTime
或ZonedDateTime
。
您应该避免使用最早版本的Java捆绑的旧日期时间类型。事实证明,它们设计糟糕,令人困惑且麻烦。现在取代了java.time类型。
但是,如果您必须与尚未更新为java.time类型的旧代码进行交互,则可以转换为/来自java.time。查看添加到旧类的新方法。
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
从java.time类型转换为java.util.Date
或java.util.Calendar
时,请注意数据丢失。这些类型仅解析为milliseconds。从纳秒到毫秒的截断是静默地执行的,从最后六个(九个)可能的数字秒数中删除。
java.util.Date utilDate = java.util.Date.from( instant ); // Caution: Data loss in truncating nanoseconds to milliseconds.
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date
,.Calendar
和& java.text.SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。
大部分java.time功能都被反向移植到Java 6& ThreeTen-Backport中的7,并进一步适应Android中的ThreeTenABP(见How to use…)。
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。
答案 1 :(得分:1)
那么,将这些微秒转换为毫秒,然后只创建一个时间戳对象呢?
long microsecs = 1474457086337977L;
long millis = TimeUnit.MILLISECONDS.convert(microsecs, TimeUnit.MICROSECONDS);
Timestamp time = new Timestamp(millis);
那不行吗?
<强> - 修改
解决答案中留下的评论:
关于Java 8的新Date Time API
首先,既然你提到你正在使用Java 8我完全同意更好的方法是使用新的Java 8 Date / Time API。但是,即使在使用Java 8时,这也是一种奢侈品,因为您仍然可以使用旧的Java日期/时间类与旧API进行交互,或者只是因为您的其余API仍在使用它们,你不想开始混合。
您的问题中不清楚您是否已经知道这一点,您似乎确定要使用java.util.Date
或java.sql.Timestamp
并且我没有质疑,我只是在处理你问题的参数。
显然,新的Java日期/时间API比旧的更好,但是有数百万行代码仍在使用旧的API并且它们有效。我再次认为这不属于答案的范围,看来你已经有了其他好的答案来解决这个问题。
关于可能的数据丢失
有一条评论提到答案可能会导致数据丢失。我认为在Java中,所有整数运算都会受到潜在的下溢或溢出的影响。我的错误可能没有提到它。
在某些情况下,TimeUnit.convert
方法可能最终导致溢出或下溢。它记录在方法中。
这意味着,一旦表示为长,毫秒数应该比微秒数小得多,对吧?
TimeUnit.convert
使用的公式如下
final long MICROS = 1000000L;
final long MILLIS = 1000L;
long microsecs = 1474457086337977L;
long millisecs = microsecs / (MICROS / MILLIS)
这意味着只有当您的微秒数确实很小时才会遇到数据丢失,例如如果你的时间少于1,000微秒。您应该验证您的代码永远不会进入这样的场景。
这个答案中留下的一个评论认为正确的答案可能应该使用纳秒,但是再一个纳秒长的值将比微秒大得多,因此,在转换为纳秒期间,您可能仍会遇到溢出。
例如,想想如果你有Long.MAX_VALUE
微秒会发生什么,你怎么能只使用Java长算法将其转换为纳秒,而不会出现溢出,因为纳秒应该是比你的{{}更大的数字。 1}}微秒?
我的观点是,无论您使用的是Java 8 Date Time还是旧的Java Date Time API,您都需要一个Long.MAX_VALUE
值来表示时间线中的一个瞬间,但long
有关于你可以去过多远或未来多远,当你在单位之间进行转换时,算术会受到下溢和溢出的影响,并且没有办法解决它,你应该注意这一点,以避免非常讨厌的错误。
再一次,我认为这是一个给定的问题,超出了问题的范围,我提出这个问题只是因为我对这个遗漏有一些贬低。
答案 2 :(得分:0)
您可以尝试使用以下代码,该代码将时间戳记作为字符串:
BigInteger b = new BigInteger("1474457086337977");
b=b.divide(new BigInteger("1000"));
String x =b.toString();
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
long milliSeconds= Long.parseLong(x);
System.out.println(milliSeconds);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliSeconds);
System.out.println(formatter.format(calendar.getTime()));
或者为了更准确,您可以使用BigDecimal:
BigDecimal b = new BigDecimal("1474457086337977");
b=b.divide(new BigDecimal("1000"));
String x =b.toString();