将 CIM_DateTime 以毫秒解析为 Java 日期 [英] Parse CIM_DateTime with milliseconds to Java Date

查看:75
本文介绍了将 CIM_DateTime 以毫秒解析为 Java 日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将从 Windows 管理界面检索到的 DateTime 值转换为 Java (1.7) 日期;最终达到自纪元以来的毫秒数.格式在此处指定.

我试图解析的一个例子是 20160513072950.782000-420 这是 2016 年 5 月 13 日 07:29:50 加上 782 毫秒,在我的本地时区(-420 分钟 = UTC-7 小时).小数点后的数字是小数秒;理论上最多 6 位微秒,但实际上只有前 4 位非零.

我最初尝试使用 SimpleDateFormat 指定我想解析的三位数毫秒:

SimpleDateFormat cimDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");日期 date = cimDateFormat.parse(s, new ParsePosition(0));

我的推理是用 SSS 指定三个毫秒数会停止解析.不幸的是,这没有用.上例中添加的时间远远超过 782 毫秒.

我最终通过将字符串修剪为所需的字符使其按预期工作:

SimpleDateFormat cimDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.S");日期 date = cimDateFormat.parse(s.substring(0, 18), new ParsePosition(0));

在这种情况下,我只包含一个 S 毫秒,但它解析了所有三个.

我在 SimpleDateFormat javadoc 中找不到任何内容清楚地解释了解析结束时发生的情况.具体问题:

  1. SSS 情况下,为什么它会继续解析超过指定数量的数字?
  2. 为什么单个 S 解析所有 3 毫秒数字?
  3. 除了像我那样截断字符串之外,还有其他方法可以告诉 SimpleDateFormat 在指定位置停止解析字符串吗?

解决方案

修改输入

据我所知,Java 的三个常见日期时间框架(旧捆绑的 java.util.Date/.Calendar/java.text.SimpleDateFormat 类、Joda-Time 框架或 java.util.Date/.Calendar/java.text.SimpleDateFormat 类)都没有.Java 8 及更高版本中内置的时间框架)允许将 UTC 偏移量作为总分钟数.

Sotirios Delimanolis 所建议,您必须修改 offset-from-UTC 将总分钟数转换为标准小时数和分钟数(和秒数——这种可能性被奇怪的人忽略了微软格式).所以 -420 应该变成 -07:00-07:00:00.

java.time

您正在使用与最早版本的 Java 捆绑在一起的麻烦的旧日期时间类.旧的类现在是遗留的,并已被 java.time 框架内置于 Java 8 及更高版本中,并且大部分反向移植到 Java6 &7 由 ThreeTen-Backport 项目和进一步适应 Android.

java.time 类的分辨率为 纳秒,最多九位数秒的小数部分.因此,处理您输入的 4-6 位小数秒没有问题.

我们的策略有两个部分:(a) 修改输入以转换从 UTC 的偏移量,以及 (b) 将修改后的输入字符串解析为日期时间对象.

修改输入

首先我们将输入从 20160513072950.782000-420 更改为 20160513072950.782000-07:00:00.我们通过提取 +- 后面的字符来实现这一点,在本例中为 420.

//修改输入以将偏移量替换为标准格式的分钟数、小时数、分钟数和秒数.字符串输入 = "20160513072950.782000-420";String offsetInMinutesAsString = input.substring ( 22 );

将其转换为long,并创建一个LocalTime对象,以便我们可以生成HH:mm:ss.

long offsetInMinutes = Long.parseLong ( offsetInMinutesAsString );LocalTime offsetAsLocalTime = LocalTime.MIN.plusMinutes ( offsetInMinutes );String offsetAsString = offsetAsLocalTime.format ( DateTimeFormatter.ISO_LOCAL_TIME );

用我们生成的字符串替换那些尾随字符.

String inputModified = ( input.substring ( 0 , 22 ) + offsetAsString );

将字符串解析为日期时间对象

定义自定义格式模式 将该字符串解析为 OffsetDateTime 对象.

//将修改后的输入解析为 OffsetDateTime.DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyyMMddHHmmss.SSSSSSZZZZZ" , Locale.US );OffsetDateTime odt = OffsetDateTime.parse ( inputModified , formatter );

转储到控制台.

System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );

<块引用>

输入:20160513072950.782000-420 |输入修改:20160513072950.782000-07:00:00 |odt: 2016-05-13T07:29:50.782-07:00

转换

我强烈建议避免使用旧的日期时间类.但是,如果您必须使用 java.util.Date 对象与旧的日期时间代码进行互操作,则可以进行转换.

寻找添加到旧类中的新方法进行转换.对于这种转换,我们使用 java.util.Date.from.我们需要为该转换方法提供 Instant 对象,UTC 时间轴上的一个时刻,分辨率为纳秒.我们可以从 OffsetDateTime 中提取一个.

Instant Instant = odt.toInstant();java.util.Date utilDate = java.util.Date.from( Instant );

有关转换的更多信息,包括漂亮的图表,请参阅另一个问题的我的回答.请记住,我们在输入字符串中仅使用 offset-from-UTC和我们的 OffsetDateTime,不是完整的时区.时区是用于处理异常的偏移规则,例如夏令时 (DST).Instantjava.util.Date 均采用 UTC(偏移量为零).

I am trying to convert a DateTime value retrieved from Windows Management Interface into a Java (1.7) Date; ultimately to milliseconds since the epoch. The format is specified here.

An example that I am trying to parse is 20160513072950.782000-420 which is 2016-05-13 at 07:29:50 plus 782 milliseconds, in my local timezone (-420 minutes = UTC-7 hours). The digits after the decimal are fractional seconds; in theory up to 6 digits of microseconds, but in practice only the first 4 digits are nonzero.

I initially attempted to parse using a SimpleDateFormat specifying the three digits of milliseconds that I wanted to parse:

SimpleDateFormat cimDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
Date date = cimDateFormat.parse(s, new ParsePosition(0));

My reasoning was that specifying the three digits of milliseconds with SSS would stop the parsing. Unfortunately, this didn't work; many more than 782 milliseconds in the above example were added.

I eventually got it to work as desired by trimming the string to the required characters:

SimpleDateFormat cimDateFormat = new SimpleDateFormat("yyyyMMddHHmmss.S");
Date date = cimDateFormat.parse(s.substring(0, 18), new ParsePosition(0));

In this case, I only included one S for milliseconds but it parsed all three.

I can't find anything in the SimpleDateFormat javadoc that clearly explains what's going on at the end of this parsing. Specific questions:

  1. Why does it keep parsing past the specified number of digits in the SSS case?
  2. Why does a single S parse all 3 millisecond digits?
  3. Other than truncating the string like I did, is there any other way of telling the SimpleDateFormat to stop parsing the string at the indicated position?

解决方案

Modify the input

As far as I know, none of the three common date-time frameworks for Java (the old bundled java.util.Date/.Calendar/java.text.SimpleDateFormat classes, the Joda-Time framework, or the java.time framework built into Java 8 and later) allow for an offset-from-UTC as a total number of minutes.

As suggested by Sotirios Delimanolis, you must modify the offset-from-UTC to convert from a number of total minutes to the standard number of hours and minutes (and seconds – a possibility ignored by that odd Microsoft format). So -420 should become -07:00 or -07:00:00.

java.time

You are using the troublesome old date-time classes bundled with the earliest versions of Java. The old classes are now legacy, and have been supplanted by the java.time framework built into Java 8 and later, and largely back-ported to Java 6 & 7 by the ThreeTen-Backport project and further adapted to Android.

The java.time classes have a resolution of nanoseconds, for up to nine digits of a decimal fraction of second. So no problem handling your inputs 4-6 digits of fractional second.

Our strategy has two parts: (a) Modify the input to convert that offset-from-UTC, and (b) Parse the modified input string as a date-time object.

Modify input

First we change the input from 20160513072950.782000-420 to 20160513072950.782000-07:00:00. We do this by extracting the characters trailing after the + or -, the 420 in this case.

// Modify the input to replace offset as a number of minutes to the standard format, a number of hours, minutes, and seconds.
String input = "20160513072950.782000-420";
String offsetInMinutesAsString = input.substring ( 22 );

Convert that to a long, and create a LocalTime object so that we can generate a string in the format of HH:mm:ss.

long offsetInMinutes = Long.parseLong ( offsetInMinutesAsString );
LocalTime offsetAsLocalTime = LocalTime.MIN.plusMinutes ( offsetInMinutes );
String offsetAsString = offsetAsLocalTime.format ( DateTimeFormatter.ISO_LOCAL_TIME );

Replace those trailing characters with our generated string.

String inputModified = ( input.substring ( 0 , 22 ) + offsetAsString );

Parse string to date-time object

Define a custom formatting pattern by which to parse that string into a OffsetDateTime object.

// Parse the modified input as an OffsetDateTime.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyyMMddHHmmss.SSSSSSZZZZZ" , Locale.US );
OffsetDateTime odt = OffsetDateTime.parse ( inputModified , formatter );

Dump to console.

System.out.println ( "input: " + input + " | inputModified: " + inputModified + " | odt: " + odt );

input: 20160513072950.782000-420 | inputModified: 20160513072950.782000-07:00:00 | odt: 2016-05-13T07:29:50.782-07:00

Convert

I strongly suggest avoiding the old date-time classes. But if you must use a java.util.Date object to interoperate with old date-time code, you can convert.

Look for new methods added to the old classes for conversion. For this conversion we use java.util.Date.from. We need to feed that conversion method a Instant object, a moment on the timeline in UTC with a resolution of nanoseconds. We can extract one from our OffsetDateTime.

Instant instant = odt.toInstant();
java.util.Date utilDate = java.util.Date.from( instant );

For more info about converting, including a nifty diagram, see my Answer to another Question. Keep in mind that we are working with only a mere offset-from-UTC in our input strings and our OffsetDateTime, not a full time zone. A time zone is an offset plus rules for handling anomalies such as Daylight Saving Time (DST). Both the Instant and the java.util.Date are in UTC (an offset of zero).

这篇关于将 CIM_DateTime 以毫秒解析为 Java 日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆