I want to parse a timestamp, like this - \"2016-03-16 01:14:21.6739\"
. But when I use the SimpleDateFormat
to parse it, I find that it outputs an i
If you have to get string as final output why not use format
instead of parse
final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
sf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date curDate = new Date();
String outputdate = sf.format(curDate);
// 2016-03-17 09:45:28.658+0000
System.out.println(outputdate);
Date strToDate = new Date();
try {
strToDate = sf.parse(outputdate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Thu Mar 17 17:11:30 MYT 2016
System.out.println(strToDate);
and instead of "yyyy-MM-dd HH:mm:ss.SSSS"
use "yyyy-MM-dd HH:mm:ss.SSSZ"
check it here https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
"yyyy-MM-dd'T'HH:mm:ss.SSSZ" 2001-07-04T12:08:56.235-0700
It seems that is not possible to use SimpleDateFormat to express times with a finer grain than the millisecond. What is happening is that as you put 6739, Java understands it as 6739 milliseconds i.e. 6 seconds and 739 milliseconds hence the 6 seconds difference observed.
Check these ones, it is explained quite well: String-Date conversion with nanoseconds Java date parsing with microsecond or nanosecond accuracy
As mentioned in the comments above your question already contains the answer: milliseconds must not have more than 3 digits otherwise it represents at least one full second already.
That your code is working is simply due to a very questionable feature of java.text.SimpleDateFormat
, the lenient (see here) option. By default a SimpleDateFormat
has setLenient
set to true
wich means that the parser will try to interpret strings that do not match the pattern 100% and will convert them to date objects by means of some heuristics. For example it will accept a date 31.04.2016
and convert it to 01.05.2016
. This feature may be nice in some situations but produces questionable results in most of the cases.
If you set lenient to false
in your code, the date string won't be parsed anymore. Making the error in the pattern more obvious:
final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
sf.setLenient(false);
String parsedate="2016-03-16 01:14:21.6739";
...
As java.util.Date
is not able to represent any precision lower than milliseconds, I think the best option for you to parse your date would be to simply strip of the last digits of your input date, if the part after the dot has more than four digits. Your code might look something like this:
final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
sf.setLenient(false);
String parsedate="2016-03-16 01:14:21.6739";
try {
// 23 is the length of the date pattern
if (parsedate.length() > 23) {
parsedate = parsedate.substring(0, 23);
}
Date outputdate = sf.parse(parsedate);
String newdate = sf.format(outputdate); //==output date is: 2016-03-16 01:14:21.673
System.out.println(newdate);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
You could try to add some rounding logic as well in order to not loose all the information of the 4th digit...
You can use String newdate = sf.format(outputdate); in place of String newdate = outputdate.toString();
LocalDateTime.parse(
"2016-03-16 01:14:21.6739".replace( " " , "T" ) // Comply with ISO 8601 standard format.
)
As others noted, java.util.Date
has millisecond resolution. That means up to 3 digits of a decimal fraction of second.
You have 4 digits in your input string, one too many. Your input value demands finer resolution such as microseconds or nanoseconds.
Instead of using the flawed, confusing, and troublesome java.util.Date/.Calendar classes, move on to their replacement: the java.time framework built into Java 8 and later.
The java.time classes have a resolution of nanosecond, up to nine digits of decimal fraction of a second. For example:
2016-03-17T05:19:24.123456789Z
Your string input is almost in standard ISO 8601 format used by default in java.time when parsing/generating textual representations of date-time values. Replace that space in the middle with a T
to comply with ISO 8601.
String input = "2016-03-16 01:14:21.6739".replace( " " , "T" );
A LocalDateTime is an approximation of a date-time, without any time zone context. Not a moment on the timeline.
LocalDateTime ldt = LocalDateTime.parse( input );
Make that LocalDateTime an actual moment on the timeline by applying the intended time zone. If meant for UTC, make an Instant
.
Instant instant = ldt.toInstant( ZoneOffset.UTC );
If meant for a particular time zone, specify a ZoneId to get a ZoneDateTime.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId );
A little off-topic but SimpleDateFormat
class is not thread safe - not only on parsing which is somewhat understandable but also on formatting. there are a lot of info on this on the net, here is one example: http://javarevisited.blogspot.co.il/2012/03/simpledateformat-in-java-is-not-thread.html. This problem will not be fixed. In Java 8 there is a whole new package java.time
with wonderful new features allowing to work with full or partial dates and times. Also there is a new class DateTimeFormatter that provides vastly improved formatting and parsing features. However, if you use java older then java 8 then the recommendation would be to use Joda time library or Apache FastDateFormat