/*I want the same Date of my String has
Tried with couple of options but nothing worked
pasting some of code here */
public void stringToDate() {
//Current format "13-FEB-20 03.21.08.100000000 PM" in Melbourne Timezone
//Required Format yyyy-dd-MM HH:mm:ss.SSS in Melbourne Timezone
String inputAM = "13-FEB-20 03.21.08.100000000 PM";
try {
DateFormat df1 = new SimpleDateFormat("dd-MMM-yy hh.mm.ss.S aa");
Date d1 = df1.parse(inputAM);
System.out.println("Date-1: " + d1); //Fri Feb 14 19:07:48 AEDT 2020
DateFormat df2 = new SimpleDateFormat("DD-MMM-yy hh.mm.ss.S aa");
Date d2 = df2.parse(inputAM);
System.out.println("Date-2: " + d2); //Tue Jan 14 19:07:48 AEDT 2020
} catch (ParseException e) {
e.printStackTrace();
}
SimpleDateFormat etDf = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSS");
TimeZone etTimeZone = TimeZone.getTimeZone("Australia/Melbourne");
etDf.setTimeZone(etTimeZone);
DateFormat df3 = new SimpleDateFormat("dd-MMM-yy HH.mm.ss.SSSSSSSSS a");
Date d3;
try {
d3 = df3.parse(inputAM);
System.out.println("Date-3: " + d3); //Fri Feb 14 07:07:48 AEDT 2020
System.out.println("Date-4: " + etDf.format(d3.getTime())); //2020-14-02 07:07:48.000
} catch (ParseException e) {
e.printStackTrace();
}
}

- 81,772
- 15
- 137
- 161

- 275
- 1
- 11
-
1I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `LocalDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Feb 26 '20 at 07:35
-
Does this answer your question? [Date object SimpleDateFormat not parsing timestamp string correctly in Java (Android) environment](https://stackoverflow.com/questions/5636491/date-object-simpledateformat-not-parsing-timestamp-string-correctly-in-java-and) This? [Timestamp convert](https://stackoverflow.com/questions/58705924/timestamp-convert) – Ole V.V. Feb 26 '20 at 07:41
2 Answers
First, for most purposes don’t convert a date and time from one string format to another. In your program keep date and time as proper date-time objects, not strings. When you accept string input, parse it first thing. Only when you need to give string output, format your date-time into a string in the required format.
Second, use java.time, the modern Java date and time API for all of your date and time work. It is so much nicer to work with than the old, poorly designed and long outdated classes including DateFormat
, SimpleDateFormat
and Date
.
Parse your input using java.time
//Current format "13-FEB-20 03.21.08.100000000 PM" in Melbourne Timezone
DateTimeFormatter currentFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("d-MMM-uu hh.mm.ss.SSSSSSSSS a")
.toFormatter(Locale.ENGLISH);
ZoneId zone = ZoneId.of("Australia/Melbourne");
String inputAM = "13-FEB-20 03.21.08.100000000 PM";
ZonedDateTime dateTime = LocalDateTime.parse(inputAM, currentFormatter).atZone(zone);
System.out.println(dateTime);
Output so far is:
2020-02-13T15:21:08.100+11:00[Australia/Melbourne]
Format using java.time
//Required Format yyyy-dd-MM HH:mm:ss.SSS in Melbourne Timezone
DateTimeFormatter requiredFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
String formatted = dateTime.format(requiredFormatter);
System.out.println(formatted);
2020-02-13 15:21:08.100
What went wrong in your code?
When I first tried your code, parsing failed for FEB
because your code doesn’t specify locale, and my Java uses a non-English default locale.
Correcting that I was able to parse the string and got the same results as you (only in my time zone). What happens: SimpleDateFormat
takes uppercase S
to mean milliseconds, 1000ths of seconds, no matter how many S
there are and no matter how many digits are in the string to be parsed. So 100 000 000 milliseconds were added to your date and time. That’s a little more than one day. So you got 14 Feb instead of 13 Feb, and also a wrong time of day. In contrast to the modern DateTimeFormatter
upper case S
means fraction of second, so it handles both SSSSSSSSS
and SSS
the way we expect.
Uppercase DD
is for day of year, so using this for parsing you got the 13th day of the year (the same as 13 January) plus your 100 000 seconds.
Uppercase HH
is for hour of day from 00 through 23. Parsing using HH
gave you 03:21 of day (same as 03:21 AM) plus your 100 000 seconds no matter that it said PM
in your string.
Link
- Oracle tutorial: Date Time explaining how to use java.time.

- 81,772
- 15
- 137
- 161
There are three major problems in your code:
- You have used
.SSSSSSSSS
for the fraction of a second whereas theSimpleDateFormat
does not support a precision beyond milliseconds (.SSS
). It also means that you need to limit the digits in the fraction of a second to three. - You have used
HH
for a time in 12-Hour format (i.e. with am/pm) whereas the correct pattern for this ishh
. The symbol,HH
is used for a time in 24-Hour format. - You have used
DD
for Day in month whereas the correct pattern for this would bedd
. The symbol,DD
is used for Day in year
Apart from this, I recommend you always use Locale
with a date parsing/formatting API because parts of a date-time string are represented in different ways in different Locale
s.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdfInput = new SimpleDateFormat("dd-MMM-yy hh.mm.ss.SSS a", Locale.ENGLISH);
Date date = sdfInput.parse("13-FEB-20 03.21.08.100 PM");
// Print Date#toString
System.out.println(date);
// Print the date-time in a custom format
SimpleDateFormat sdfOutput = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSS", Locale.ENGLISH);
System.out.println(sdfOutput.format(date));
// If required, format date with a timezone
SimpleDateFormat sdfOutputWithTz = new SimpleDateFormat("yyyy-dd-MM HH:mm:ss.SSS[zzzz]", Locale.ENGLISH);
sdfOutputWithTz.setTimeZone(TimeZone.getTimeZone("Australia/Melbourne"));
System.out.println(sdfOutputWithTz.format(date));
}
}
Output:
Thu Feb 13 15:21:08 GMT 2020
2020-13-02 15:21:08.100
2020-14-02 02:21:08.100[Australian Eastern Daylight Time]
Some facts about legacy API:
- The
java.util.Date
object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namelyJanuary 1, 1970, 00:00:00 GMT
(or UTC). When you print an object ofjava.util.Date
, itstoString
method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone toSimpleDateFormat
and obtain the formatted string from it. - The
java.util
date-time API and their formatting API,SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API◊ .
Using modern date-time API:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtfInput = new DateTimeFormatterBuilder()
.parseCaseInsensitive() // For case-insensitive (e.g. AM/am) parsing
.appendPattern("dd-MMM-uu hh.mm.ss.SSSSSSSSS a")
.toFormatter(Locale.ENGLISH);
// Parse the date-time string
LocalDateTime ldt = LocalDateTime.parse("13-FEB-20 03.21.08.100000000 PM", dtfInput);
// Print LocalDateTime#toString
System.out.println(ldt);
// Print the date-time in a custom format
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-dd-MM HH:mm:ss.SSS", Locale.ENGLISH);
System.out.println(ldt.format(dtfOutput));
// If required, convert the LocalDateTime to ZonedDateTime
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Australia/Melbourne"));
System.out.println(zdt);
}
}
Output:
2020-02-13T15:21:08.100
2020-13-02 15:21:08.100
2020-02-13T15:21:08.100+11:00[Australia/Melbourne]
Note:
- If your date-time string has always 9 digits for the fraction of a second, you can replace
.SSSSSSSSS
with.n
. - For
DateTimeFormatter
, the symbol,u
means year whereas the symbol,y
means year-of-era. It doesn't make any difference for a year in the AD era, but it matters for a year in the BC era. Check this answer to learn more about it. LocalDateTime
does not have timezone information. If you want to display the timezone information, you should consider usingZonedDateTime
orOffsetDateTime
. The following table shows an overview of java.time data-time types:
Learn more about the modern date-time API from Trail: Date Time.
◊ For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

- 71,965
- 6
- 74
- 110