[英]Converting string date to string in yyyy-MM-dd'T'HH:mm:ss.SSSSSS format in java 7
I have the following date 我有以下日期
2017-08-23-11.19.02.234850 2017-08-23-11.19.02.234850
it has the following date format 它具有以下日期格式
yyyy-MM-dd-HH.mm.ss.SSSSSS yyyy-MM-dd-HH.mm.ss.SSSSSS
What I want to do is to convert the date to format yyyy-MM-dd'T'HH:mm:ss.SSSSSS 我要做的是将日期转换为yyyy-MM-dd'T'HH:mm:ss.SSSSSS
I have the following code 我有以下代码
public static void main(String[] args) {
String strDate = "2017-08-23-11.19.02.234850";
String dateFmt = "yyyy-MM-dd-HH.mm.ss.SSSSSS";
System.out.println("converted Date: " + convertDate(strDate, dateFmt));
}
public static String convertDate(String strDate, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
sdf.setLenient(true);
try {
Date dateIn = sdf.parse(strDate);
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS").format(dateIn);
}catch(ParseException e) {
e.printStackTrace();
}
return "";
}
the result is 结果是
converted Date: 2017-08-23T11:22:56.000850
input date 2017-08-23-11.19.02.234850 converted date 2017-08-23T11:22:56.000850 doesn't look the same, it seems java is rounding the milliseconds besides if I turn lenient off for date validation 输入日期2017-08-23-11.19.02.234850转换日期2017-08-23T11:22:56.000850看起来不一样,似乎Java舍入了毫秒数,如果我关闭宽大日期验证
sdf.setLenient(false); sdf.setLenient(false);
I get the following 我得到以下
java.text.ParseException: Unparseable date: "2017-08-23-11.19.02.234850"
at java.text.DateFormat.parse(Unknown Source)
at mx.santander.canonical.datamodel.enums.Main.convertDate(Main.java:74)
at mx.santander.canonical.datamodel.enums.Main.main(Main.java:66)
converted Date:
How to build a function which validates and converts date strings like this in a proper way? 如何建立一个以正确的方式验证和转换日期字符串的函数?
EDIT: 编辑:
I added a new function to obtain results 我添加了一个新功能以获得结果
/**
* Gets the ISO 8601 date str from string.
*
* @param strDate the str date
* @return the ISO 8601 date str from string
*/
private String getISO8601DateStrFromString (String strDate) {
String responseISO8601Date = "";
if(strDate == null || "".equals(strDate.trim())) {
return responseISO8601Date;
}
try {
String strDtWithoutNanoSec = strDate.substring(0, strDate.lastIndexOf("."));
String strDtNanoSec = strDate.substring(strDate.lastIndexOf(".") + 1, strDate.length());
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss");
formatter.setLenient(false);
Date date = formatter.parse(strDtWithoutNanoSec);
Timestamp t = new Timestamp(date.getTime());
t.setNanos(Integer.parseInt(strDtNanoSec));
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'");
NumberFormat nf = new DecimalFormat("000000");
responseISO8601Date = df.format(t.getTime()) + nf.format(t.getNanos());
} catch (ParseException | StringIndexOutOfBoundsException | NumberFormatException e) {
String errorMsg = String.format("The date provided for conversion to ISO 8601 format [%s] is not correct", strDate);
System.out.println(errorMsg);
}
return responseISO8601Date;
}
What I get: 我得到的是:
Uptadet date 2017-12-20T11:19:02.234850 更新日期2017-12-20T11:19:02.234850
As others have already mentioned, your requirement does not fit the use of Date
and SimpleDateFormat
since these only support milliseconds, that is, three decimals on the seconds, where you have six decimals (microseconds). 正如其他人已经提到的那样,您的要求不适合使用Date
和SimpleDateFormat
因为它们仅支持毫秒,即秒数为三位小数,其中您有六位小数(微秒)。 So we need to find some other way. 因此,我们需要找到其他方法。 This is basically a good idea anyway, since Date
and SimpleDateFormat
are long outdated, and today we have better tools for the job. 无论如何,这基本上是一个好主意,因为Date
和SimpleDateFormat
早已过时,并且今天我们有更好的工具来完成这项工作。
I have got two suggestions for you. 我有两个建议给你。
Even in Java 7 I think that it's a good idea to use the modern Java date and time API that came out with Java 8, AKA JSR-310. 即使在Java 7中,我也认为使用Java 8(即AKA JSR-310)附带的现代Java日期和时间API是一个好主意。 Can you do that? 你能做到吗? Certainly; 当然; use the backport for Java 6 and 7, ThreeTen Backport . 将backport用于Java 6和7, ThreeTen Backport 。 The modern API supports anything from 0 through 9 decimals on the seconds, and the code is straightforward when you know how: 现代的API支持秒显示从0到9的十进制数,并且当您知道如何时,代码就很简单:
private static DateTimeFormatter inputParser
= DateTimeFormatter.ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS");
private static DateTimeFormatter outputFormatter
= DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
public static String convertDate(String strDate) {
return LocalDateTime.parse(strDate, inputParser)
.format(outputFormatter);
}
I am using your own two format pattern strings. 我正在使用自己的两种格式模式字符串。 convertDate("2017-08-23-11.19.02.234850")
returns 2017-08-23T11:19:02.234850
. convertDate("2017-08-23-11.19.02.234850")
返回2017-08-23T11:19:02.234850
。
There is a simplification possible: Since the format you want to obtain, conforms with ISO 8601, you don't need an explicit formatter for it. 有一个可能的简化:由于您要获取的格式符合ISO 8601,因此不需要显式格式化程序。 The modern classes understand and produce ISO 8601 formats natively, so you may use: 现代类可以本地理解和生成ISO 8601格式,因此您可以使用:
return LocalDateTime.parse(strDate, inputParser).toString();
However, if the decimals on the seconds happened to end in 000
, this will not print the last three zeroes. 但是,如果秒的小数点恰好以000
结尾,则不会输出最后三个零。 So if six decimals are required even in this case, use the formatter. 因此,即使在这种情况下也需要六位小数,请使用格式化程序。
If you don't want to rely on an external library, even temporarily until once you upgrade to Java 8 (or 9), your job can be done with a regular expression: 如果您不想依赖外部库,即使只是暂时不依赖于外部库,直到升级到Java 8(或9)后,都可以使用正则表达式来完成工作:
return strDate
.replaceFirst("^(\\d{4}-\\d{2}-\\d{2})-(\\d{2})\\.(\\d{2})\\.(\\d{2}\\.\\d{6})$",
"$1T$2:$3:$4");
It's less elegant and harder to read, and it doesn't offer the level of input validation you get from using a proper date and time API. 它不那么优雅,更难阅读,并且不提供使用正确的日期和时间API所获得的输入验证级别。 Other than that, it's a way through. 除此之外,这是一条路。
As others have said, java.sql.Timestamp
offers nanosecond precision and thus will hold your date-time. 就像其他人所说的那样, java.sql.Timestamp
提供了纳秒级的精度,因此将保留您的日期时间。 Parsing your string into a Timestamp
isn't straightforward, though, so I don't think it's worth the trouble. 但是,将字符串解析为Timestamp
并不是一件容易的事,因此我认为这样做不值得。 Usagi Miyanmoto correctly identifies Timestamp.valueOf()
as the method to use, but before you could do that, you would have change the format, so you would end up changing the format twice instead of just once. Usagi Miyanmoto正确地将Timestamp.valueOf()
标识为要使用的方法,但是在您可以执行此操作之前,您已经更改了格式,因此最终将更改格式两次,而不是一次。 Or maybe three times since Timestamp
also doesn't produce your desired ISO 8601 format readily. 也许是三遍,因为Timestamp
也无法轻松生成所需的ISO 8601格式。 Additionally you would need to decide a time zone for the timestamp, but I assume you could do that without any trouble. 另外,您需要确定时间戳的时区,但是我认为您可以做到这一点而没有任何麻烦。
If you needed to keep the the date-time around, a Timestamp
object might be worth considering, but again, it's a long outdated class. 如果您需要保持日期时间不变,则可能值得考虑使用Timestamp
对象,但这又是一个过时的类。 In any case, for reformatting alone, I certainly would not use it. 无论如何,仅凭格式重新格式化,我当然不会使用它。
SimpleDateFormat
understood 234850 as milliseconds, that is, 234 seconds 850 milliseconds. SimpleDateFormat
将234850理解为毫秒,即234秒为850毫秒。 So it added 234 seconds to your time, 11:19:02. 因此,它为您的时间增加了234秒11:19:02。 And then printed the remaining 850 milliseconds in 6 decimal places as you had requested. 然后按要求将剩余的850毫秒打印在小数点后6位。
Date has precision only till milli seconds. 日期只能精确到毫秒。 Please use timestamp instead - it has precision till nano seconds, which is expected in your case. 请改用timestamp-它的精度可以达到纳秒,这在您的情况下是可以预期的。
Please refer this answer - precision till nano seconds 请参考此答案- 精确到纳秒
A thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value. 围绕java.util.Date的瘦包装器,该包装器允许JDBC API将其标识为SQL TIMESTAMP值。 It adds the ability to hold the SQL TIMESTAMP fractional seconds value, by allowing the specification of fractional seconds to a precision of nanoseconds . 通过允许小数秒的精度达到纳秒精度,它增加了保存SQL TIMESTAMP小数秒值的能力。 A Timestamp also provides formatting and parsing operations to support the JDBC escape syntax for timestamp values. 时间戳还提供格式化和解析操作,以支持时间戳值的JDBC转义语法。
SimpleDateFormat
of Java does not support microsecond in pattern. Java的SimpleDateFormat
不支持微秒模式。
java.util.Date format SSSSSS: if not microseconds what are the last 3 digits? java.util.Date格式SSSSSS:如果不是毫秒,则最后3位数字是多少?
You have several choices: 您有几种选择:
That result you got is expected. 您得到的结果是预期的。 In your format string S
were used. 在您的格式字符串S
被使用。 S
is for milliseconds, hat is thousandths of seconds, and in this case the number of S
's does not matter for parsing. S
为毫秒,hat为千分之一秒,在这种情况下, S
的数目对于解析而言无关紧要。
Your input string ends with 11.19.02.234850
, the last part is interpreted as an integer value, and added to the date and time as milliseconds. 您输入的字符串以11.19.02.234850
,最后一部分被解释为整数值,并以毫秒为单位添加到日期和时间。 That is as 234.850
seconds. 那就是234.850
秒。 Now, if you add 234
secs to 11:19:02
, it becomes 11:22:56
, just as you got in the result... 现在,如果您将234
秒添加到11:19:02
,则它变为11:22:56
,就像您得到的结果一样...
You cannot make a SimpleDateFormat
mask that can parse microseconds into a Date
, and Date
cannot hold microseconds value either. 您不能创建可以将微秒解析为Date
的SimpleDateFormat
掩码,并且Date
也不可以包含微秒的值。
You have to choose, whether you want to use Date
, or really need the finer then milliseconds resolution? 您必须选择是否要使用Date
,还是真的需要更好的毫秒级分辨率?
If you stick with Date
, you should truncate the string of the last 3 characters. 如果坚持使用Date
,则应截断最后3个字符的字符串。
Or you could use java.sql.Timestamp
, which has a valueOf()
method , hat uses SQL timestamp format. 或者,您可以使用具有valueOf()
方法的 java.sql.Timestamp
,并使用SQL时间戳格式。
Unfortunately it is not exactly he same as yours (being yyyy-[m]m-[d]d hh:mm:ss[.f...]
)... 不幸的是,他与您的并不完全相同(是yyyy-[m]m-[d]d hh:mm:ss[.f...]
)...
Another way could be to split the string by separators (like [-.]
), parse them to integers, and use hese integers with the Timestamp()
constructor ... 另一种方法是用分隔符(如[-.]
)分割字符串,将其解析为整数,然后将这些整数与Timestamp()
构造函数一起使用 ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.