java.time
Update:
Thanks to Ole V.V.
For a more general solution, replace .parseDefaulting(ChronoField.DAY_OF_MONTH, date.getDayOfMonth())
with .parseDefaulting(ChronoField.ALIGNED_WEEK_OF_MONTH, 1)
which will also simplify the solution by removing the need to obtain the LocalDate
first.
Demo:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("E MMM H:m:s")
.appendLiteral(' ')
.appendZoneText(TextStyle.FULL)
.appendLiteral(' ')
.appendPattern("u")
.parseDefaulting(ChronoField.ALIGNED_WEEK_OF_MONTH, 1)
.toFormatter(Locale.ENGLISH);
// Test
Stream.of(
"Mon Jan 16:20:12 India Standard Time 2014",
"Mon Feb 16:20:12 India Standard Time 2014"
).forEach(s -> System.out.println(ZonedDateTime.parse(s, dtf)));
}
}
Output:
2014-01-06T16:20:12+05:30[Asia/Kolkata]
2014-02-03T16:20:12+05:30[Asia/Kolkata]
Original answer:
The legacy date-time API (java.util
date-time types and their formatting API, SimpleDateFormat
) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time
, the modern date-time API*.
Solution using the modern API:
Your date-time string does not have day-of-month. It means that you need to provide a day-of-month to the DateTimeFormatter
which you can do by using DateTimeFormatterBuilder#parseDefaulting
. In order to obtain the first Monday of the month, the idiomatic way is to use TemporalAdjusters.firstInMonth
.
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "Mon Jan 16:20:12 India Standard Time 2014";
LocalDate date = LocalDate.of(2014, Month.JANUARY, 1)
.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseDefaulting(ChronoField.DAY_OF_MONTH, date.getDayOfMonth())
.appendPattern("E MMM H:m:s")
.appendLiteral(' ')
.appendZoneText(TextStyle.FULL)
.appendLiteral(' ')
.appendPattern("u")
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
}
}
Output:
2014-01-06T16:20:12+05:30[Asia/Kolkata]
For any reason, if you need to convert this object of ZonedDateTime
to an object of java.util.Date
, you can do so as follows:
Date date = Date.from(zdt.toInstant());
Learn more about the 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.