Java SimpleDateformatter with 10 decimals after the seconds, cannot convert to Date
There are multiple problems at the moment. I'd strongly recommend using java.time
for as much work as possible, although even that doesn't make this easy.
As you say, your value has 10 digits for "fraction of a second" - which means it goes down to 10th-of-a-nanosecond precision. That's highly unusual to start with, in my experience - and I don't think Java can handle that, even with java.time
.
I suspect you'll need to massage the data first, down to 9 digits of precision. At that point, it's fairly straightforward to parse the value to a ZonedDateTime
:
// Note this only has 9 digits of precision, not the original 10
String text = "2018-11-02 6:05:59.154116215 PM";
ZoneId zone = ZoneId.of("Asia/Colombo");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"yyyy-MM-dd h:mm:ss.SSSSSSSSS a", Locale.US)
.withZone(zone);
ZonedDateTime parsed = ZonedDateTime.parse(text, formatter);
System.out.println(parsed);
Note how I've provided SSSSSSSSS
as the fraction-of-a-second part, to handle all 9 digits. Also note the use of h
instead of HH
- HH
would mean "24-hour hour of day, with 0 padding" - neither part of which is true for your original value, which uses "6" for 6pm. It's very rare that you would want to combine H
or HH
with a
.
That code gives you a ZonedDateTime
, which you could convert into a Date
like this:
Date date = Date.from(parsed.toInstant());
I'd recommend you don't do that unless you really, really need to for interop reasons though; the Date
API is nasty in various ways.
Which date pattern in java can produce this date result? (seven digits after seconds)
First point, get rid of SimpleDateFormat
. That class is notoriously troublesome and long outdated. Also there is no way that SimpleDateFormat
can produce 7 decimals on the seconds.
Second point, you probably don’t need to print 7 decimals on the seconds. Your format exemplified through 2019-12-18T17:11:24.2646051+03:30
is ISO 8601. In ISO 8601 the number of decimals on the seconds is free, so everyone should accept if you give them a string with 3 decimals, 9 decimals or no decimals at all (in the last case leave out the decimal point too).
java.time
So the easy solution is:
String desiredString
= OffsetDateTime.now(ZoneId.systemDefault()).toString();
System.out.println(desiredString);
Output when I ran the code just now:
2019-12-28T11:46:07.308+01:00
I am using java.time, the modern Java date and time API. And I am exploiting the fact that the toString
methods of the date and time classes of java.time print ISO 8601 format. So we need no explicit formatter so far.
If you do want or need 7 decimals, do use a DateTimeFormatter
:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendPattern("HH:mm:ss.SSSSSSSXXX")
.toFormatter();
String desiredString = OffsetDateTime.now(ZoneId.systemDefault())
.format(formatter);
2019-12-28T11:48:52.3840000+01:00
It is possible to specify the formatter using a format pattern string only, but I prefer to reuse the built-in ISO_LOCAL_DATE
formatter for the date part also when the code gets a few lines longer.
Links
- Oracle tutorial: Date Time explaining how to use java.time.
- Wikipedia article: ISO 8601
Parse String to Date with Different Format in Java
Take a look at SimpleDateFormat
. The code goes something like this:
SimpleDateFormat fromUser = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
String reformattedStr = myFormat.format(fromUser.parse(inputString));
} catch (ParseException e) {
e.printStackTrace();
}
Java: Date parsing, why do I get an error
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
worked for me. With "SSSZ" instead of "SZ" at the end of the pattern.
Change date from MM/dd to yyyy-MM-dd'T'HH:mm:ss.SSZ in Java
In the question, the date format pattern indicates a desire for 2-digit fractional seconds. SimpleDateFormat
cannot do that.
The newer Java 8 Time API can, and you should be using that anyway.
If you're running on Java 6 or 7, get the ThreeTen-Backport library.
To parse a MM/dd
formatted string and get a full timestamp with current year and time-of-day, in the default time zone, use the following code:
String strDate = "06/05";
MonthDay monthDay = MonthDay.parse(strDate, DateTimeFormatter.ofPattern("MM/dd"));
ZonedDateTime date = ZonedDateTime.now().with(monthDay);
System.out.println(date.format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSZ")));
Sample Output
2020-06-05T14:52:48.45-0400
Java problem with Java.util.Date and Java.util.TimeZone
tl;dr
java.time.OffsetDateTime.parse( "2020-04-11T14:52:34.8121672+00:00" )
See this code run live at IdeOne.com.
Details
Never use java.util.Date
. That flawed class was supplanted years ago by the modern java.time classes defined in JSR 310. Specifically replaced by java.time.Instant
.
Avoid setting the JVM’s current default time zone. Doing so immediately affects all other code in all threads of all apps running in that JVM. Write your code such that you never depend on the default time zone. Always specify your desired/expected time zone.
No need to define this custom formatting pattern: "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX"
. That format is defined in the ISO 8601 standard, used by default in java.time when parsing/generating text.
By convention, the decimal fractions are written in groups of three digits. So suggest to the publisher of your data writing that textual value as 2020-04-11T14:52:34.812167200+00:00
rather than 2020-04-11T14:52:34.8121672+00:00
. And congratulate the publisher on using both the hours and the minutes of the offset, as well as the colon. While technically optional in ISO 8601, including them maximizes compatibility with various date-time handling libraries in the real world.
Your format is asking for hundreds of nanoseconds. But the legacy date-time types resolve to mere milliseconds (thousandths of a second). So you were pressing a square peg into a round hole. Fortunately, java.time resolves to nanoseconds (billionths of a second). So we can handle parsing your input.
Parse your particular input as a OffsetDateTime
.
OffsetDateTime odt = OffsetDateTime.parse( "2020-04-11T14:52:34.8121672+00:00" ) ;
Generate a string in standard ISO 8601 format.
String output = odt.toString() ;
2020-04-11T14:52:34.812167200Z
Convert to the terrible legacy java.util.Date
only if you must. Find new conversion methods added to the old classes.
java.util.Date juDate = Date.from( odt.toInstant() ) ;
All of this has been addressed many many times on Stack Overflow. Please search more thoroughly before posting. And, search to learn more.
Converting string date to string in yyyy-MM-dd'T'HH:mm:ss.SSSSSS format in java 7
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). 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.
I have got two suggestions for you.
java.time
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. Can you do that? Certainly; use the backport for Java 6 and 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:
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
.
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. The modern classes understand and produce ISO 8601 formats natively, so you may use:
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. So if six decimals are required even in this case, use the formatter.
Regular expression
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:
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. Other than that, it’s a way through.
java.sql.Timestamp?
As others have said, java.sql.Timestamp
offers nanosecond precision and thus will hold your date-time. Parsing your string into a Timestamp
isn’t straightforward, though, so I don’t think it’s worth the trouble. 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. Or maybe three times since Timestamp
also doesn’t produce your desired ISO 8601 format readily. 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. In any case, for reformatting alone, I certainly would not use it.
What happened in your code?
SimpleDateFormat
understood 234850 as milliseconds, that is, 234 seconds 850 milliseconds. So it added 234 seconds to your time, 11:19:02. And then printed the remaining 850 milliseconds in 6 decimal places as you had requested.
How to display a date mm/dd/yy as a decimal in Java?
Avoid legacy date-time classes
You are using old date-time classes that have proven to be troublesome, confusing, and flawed.
The old Calendar
and Date
classes are now legacy. Supplanted by the java.time classes.
java.time
Use the java.time classes for date-time work.
Caveat: I do not recommend representing a span of time as a decimal number. Counting a span of time as something like “1.062 years later” has no utility that I know of. Instead I suggest using the standard ISO 8601 format for a textual representation (PnYnMnDTnHnMnS
). Nevertheless, I took on this Question as a puzzle challenge.
To obtain a decimal fraction representing a fraction of the year, use the Period
and Duration
classes, with Year
helping out. The strategy is to get a fraction of year and determine the length of that fractional year in nanoseconds. Divide that number by the number of nanoseconds in that particular year (years vary in length by Leap Year and by anomalies such as redefinition of time zone), to get our decimal fraction. Add the total number of whole years for a result.
Determine the start and stop of our span of time.
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdtStart = ZonedDateTime.of ( 2015 , 2 , 21 , 12 , 34 , 56 , 0 , z );
ZonedDateTime zdtStop = ZonedDateTime.of ( 2016 , 3 , 15 , 12 , 34 , 56 , 0 , z );
Get the count of whole years via Period
.
Period p = Period.between ( zdtStart.toLocalDate () , zdtStop.toLocalDate () );
int years = p.getYears ();
Now focus on the fraction of a year. Add the number of whole years to the starting moment to get the start of that last fractional year.
ZonedDateTime zdtStartFractional = zdtStart.plusYears ( years );
Get the span of time, unattached from timeline, between our start of fractional year and the stopping point of our original span.
Duration fractionalYear = Duration.between ( zdtStartFractional , zdtStop );
Calculate our divisor, the length of this particular year in nanoseconds. Get the moment the year starts, and get a year later when following year starts.
ZonedDateTime zdtFractionalYear_StartOfYear = zdtStartFractional.with ( TemporalAdjusters.firstDayOfYear () ).toLocalDate ().atStartOfDay ( z );
Duration wholeYear = Duration.between ( zdtFractionalYear_StartOfYear , zdtFractionalYearStart.plusYears ( 1 ) );
Get the nanoseconds. To avoid the extraneous extra digits of floating point technology, we avoid float
/Float
and double
/Double
, using BigDecimal
for accuracy. Specify the scale (number of decimal fraction digits) you want in your result; here we use 32
arbitrarily.
BigDecimal fractionalYearAsNanos = new BigDecimal ( fractionalYear.toNanos () );
BigDecimal wholeYearAsNanos = new BigDecimal ( wholeYear.toNanos () );
BigDecimal ratio = fractionalYearAsNanos.divide ( wholeYearAsNanos , 32 , RoundingMode.HALF_EVEN );
BigDecimal result = ratio.add ( new BigDecimal ( years ) );
Dump to console.
System.out.println ( zdtStart + "/" + zdtStop );
System.out.println ( "Years: " + result.toPlainString () );
2015-02-21T12:34:56-05:00[America/Montreal]/2016-03-15T12:34:56-04:00[America/Montreal]
Years: 1.06272768670309653916211293260474
See live code in IdeOne.com.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
- Java SE 8 and SE 9 and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
- See How to use….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
Parsing string to date: Illegal pattern character 'T'.
Given your input of 2014-09-17T12:00:44.0000000Z
, it is not sufficient to escape the letter T
only. You also have to handle the trailing Z
. But be aware, this Z
is NOT a literal, but has the meaning of UTC+00:00
timezone offset according to ISO-8601-standard
. So escaping Z
is NOT correct.
SimpleDateFormat
handles this special char Z
by pattern symbol X
. So the final solution looks like:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSX");
Date d = sdf.parse("2014-09-17T12:00:44.0000000Z");
System.out.println(d); // output: Wed Sep 17 14:00:44 CEST 2014
Note that the different clock time is right for timezone CEST
(toString()
uses system timezone), and that the result is equivalent to UTC-time 12:00:44
. Furthermore, I had to insert seven symbols S in order to correctly process your input which pretends to have precision down to 100ns
(although Java pre 8 can only process milliseconds).
Related Topics
How to Check If a Java 8 Stream Is Empty
Android - Running a Background Task Every 15 Minutes, Even When Application Is Not Running
Simplifying the If-Else Condition Using Java Functional Style Programming
How to Read Empty Cells of an Excel File Using Poi
Status Expected:<200> But Was:<404> in Spring Test
Avoid Keycloak Default Login Page and Use Project Login Page
How to Sort Arraylist of Objects by Timestamp and Get Last Five Elements
At Runtime, Find All Classes in a Java Application That Extend a Base Class
How to Execute SQL Script File in Java
Creating Random Numbers With No Duplicates
How to Mock Resultset and Populate It Using Mockito in Java
Java Properties - How to Create Dynamic Properties
How to Find Max Date in List<Object>
How to Call a Function Only After the Previous Function Is Fully Executed in Java
How to Clean Project Cache in Intellij Idea Like Eclipse'S Clean
How to Update a Jsf Component from a Jsf Backing Bean Method