在Java或Scala中将微秒字符串转换为日期

时间:2016-09-24 11:31:53

标签: java scala

如何在Java / Scala中将时间戳(以微秒为单位)转换为日期。 我的目标是比较两个时间戳并找出它们之间的差异。 我正在使用java 8和示例Timestamp字符串是1474457086337977。 我想将其转换为Date或Timestamp实例。

3 个答案:

答案 0 :(得分:6)

TL;博士

Instant.EPOCH.plus( 
    Duration.ofNanos( 
        TimeUnit.MICROSECONDS.toNanos( 
            Long.parse( "1474457086337977" ) ) ) )

java.time

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的微秒数转换为InstantInstant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds。这意味着最多九位小数。

Instant类有一个方便的静态方法,可以从count of whole secondscount of whole seconds plus a fractional second in nanosecondscount 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类OffsetDateTimeZonedDateTime

转换为旧版日期时间类型

您应该避免使用最早版本的Java捆绑的旧日期时间类型。事实证明,它们设计糟糕,令人困惑且麻烦。现在取代了java.time类型。

但是,如果您必须与尚未更新为java.time类型的旧代码进行交互,则可以转换为/来自java.time。查看添加到旧类的新方法。

java.sql.Timestamp ts = java.sql.Timestamp.from( instant );

从java.time类型转换为java.util.Datejava.util.Calendar时,请注意数据丢失。这些类型仅解析为milliseconds。从纳秒到毫秒的截断是静默地执行的,从最后六个(九个)可能的数字秒数中删除。

java.util.Date utilDate = java.util.Date.from( instant );  // Caution: Data loss in truncating nanoseconds to milliseconds.

关于java.time

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

现在位于Joda-Timemaintenance 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.Datejava.sql.Timestamp并且我没有质疑,我只是在处理你问题的参数。

显然,新的Java日期/时间API比旧的更好,但是有数百万行代码仍在使用旧的API并且它们有效。我再次认为这不属于答案的范围,看来你已经有了其他好的答案来解决这个问题。

关于可能的数据丢失

有一条评论提到答案可能会导致数据丢失。我认为在Java中,所有整数运算都会受到潜在的下溢或溢出的影响。我的错误可能没有提到它。

在某些情况下,TimeUnit.convert方法可能最终导致溢出或下溢。它记录在方法中。

  • 纳秒是十亿分之一秒(1/1000000000)
  • 微秒是百万分之一秒(1/1000000)。
  • 毫秒是千分之一秒(1/1000)

这意味着,一旦表示为长,毫秒数应该比微秒数小得多,对吧?

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();