Question
How can I convert a String in the format "January 2, 2010" into a date in Java?
My end goal is to extract the month, day, and year as integers and convert the date into a time value. For example, I was considering code like this:
Date date = new Date();
date.setMonth(...);
date.setYear(...);
date.setDay(...);
long currentTime = date.getTime();
What is the best approach for parsing this kind of date string in Java?
Short Answer
By the end of this page, you will understand how to parse a human-readable date string such as "January 2, 2010" in Java, why manually setting fields on Date is not the best approach, and how to use the modern Java date-time API to safely extract year, month, and day or convert the result to a timestamp when needed.
Concept
Java date parsing means converting text like "January 2, 2010" into a structured date object that Java can understand.
The key idea is that a date string is just text until you tell Java what pattern it follows. In this case:
Januaryis the full month name2is the day of the month2010is the year
So Java needs a formatter pattern that matches that shape.
In older Java code, developers often used java.util.Date and SimpleDateFormat. That works, but modern Java prefers the java.time package introduced in Java 8.
Why this matters:
- Parsing lets your program accept user input or file data.
- Structured date objects are safer than manually splitting strings.
- Modern APIs avoid many bugs found in older
Datemethods.
Important note: methods like Date#setMonth(), Date#setYear(), and similar older setters are considered outdated and confusing. They have odd behavior, such as zero-based months and year offsets in some cases. In real Java code, you should usually parse into LocalDate first, then convert only if needed.
Mental Model
Think of a date formatter like a reading template.
If someone gives you the text "January 2, 2010", you need instructions that say:
- first read a full month name
- then read a day number
- then read a 4-digit year
Without that template, Java just sees a plain string.
A good mental model is:
String= raw label on a boxDate/LocalDate= the actual organized contentsFormatter= the instructions for opening and arranging the contents correctly
So you do not manually build the date piece by piece unless you really need to. Usually, you let the formatter read the whole string for you.
Syntax and Examples
The modern Java approach uses LocalDate and DateTimeFormatter.
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String input = "January 2, 2010";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse(input, formatter);
int month = date.getMonthValue();
int day = date.getDayOfMonth();
int year = date.getYear();
System.out.println(date); // 2010-01-02
System.out.println(month); // 1
System.out.println(day); // 2
System.out.println(year); // 2010
}
}
Pattern explanation:
MMMM= full month name likeJanuaryd= day of month like2yyyy= 4-digit year
If you must work with the older Date class, you can still parse the string:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
String input = "January 2, 2010";
SimpleDateFormat formatter = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
Date date = formatter.parse(input);
long time = date.getTime();
System.out.println(date);
System.out.println(time);
}
}
This older version works, but LocalDate is the preferred choice for a date without a time.
Step by Step Execution
Consider this example:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String input = "January 2, 2010";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date.getYear());
System.out.println(date.getMonthValue());
System.out.println(date.getDayOfMonth());
}
}
What happens step by step:
inputstores the raw text:"January 2, 2010".DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH)creates parsing rules.MMMMexpects a full month name.dexpects the day number.yyyyexpects the year.
LocalDate.parse(input, formatter)reads the string using those rules.- Java creates a
LocalDaterepresenting January 2, 2010. date.getYear()returns2010.date.getMonthValue()returns1.date.getDayOfMonth()returns2.
If you later need a timestamp, you must add a time and time zone because LocalDate only represents a calendar date, not a moment in time.
Example:
import java.time.LocalDate;
import java.time.ZoneId;
LocalDate date = LocalDate.of(2010, 1, 2);
long timestamp = date.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
This means: take the date, use the start of the day in a specific time zone, then convert it to milliseconds since the Unix epoch.
Real World Use Cases
Date parsing is common in many kinds of Java programs:
- Web forms: a user enters a date like
January 2, 2010 - CSV imports: a file contains date columns as text
- APIs: incoming JSON or query parameters contain dates as strings
- Reports: analytics tools convert text dates into sortable values
- Scheduling systems: appointments or deadlines start as human-readable strings
Examples:
- A payroll app parses employee start dates.
- A booking system parses check-in dates.
- A log processing script turns text dates into timestamps.
- A REST API validates and stores a birth date sent as a string.
Real Codebase Usage
In real projects, developers usually avoid manually calling old Date setter methods. Instead, they follow safer patterns.
Common patterns include:
- Parse once, use many times: convert the input string into a
LocalDateimmediately. - Validation: reject invalid date strings early.
- Guard clauses: return an error if parsing fails.
- Conversion only at boundaries: use
Dateor timestamps only when interacting with legacy libraries or databases. - Locale-aware parsing: specify
Locale.ENGLISHwhen month names are written in English.
Example with validation:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
public class DateParser {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
public static LocalDate parseDate(String input) {
if (input == null || input.isBlank()) {
throw new IllegalArgumentException("Date string cannot be empty");
}
try {
return LocalDate.parse(input, FORMATTER);
} catch (DateTimeParseException e) {
throw new IllegalArgumentException("Invalid date format. Expected example: January 2, 2010", e);
}
}
}
This style is common because it keeps parsing logic in one place and makes errors easier to handle.
Common Mistakes
Beginners often run into these problems when working with dates in Java.
1. Using old Date setter methods
Broken approach:
Date date = new Date();
date.setMonth(1);
date.setYear(2010);
Why it is a problem:
- Old
Datesetters are deprecated in practice. - They are confusing and easy to misuse.
- Some values are offset or zero-based.
Better approach:
LocalDate date = LocalDate.of(2010, 1, 2);
2. Forgetting the locale for month names
Broken code:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy");
Why it can fail:
Januaryis an English month name.- If the system default locale is not English, parsing may fail.
Better:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
3. Using the wrong pattern letters
Broken code:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM d, yyyy", Locale.ENGLISH);
Why it is wrong:
MMexpects a numeric month like01MMMMexpects a full month name likeJanuary
Correct:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
4. Assuming a date automatically includes a time
A LocalDate has no hour, minute, second, or time zone.
If you need milliseconds since epoch, you must specify a time and zone:
long millis = date.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
5. Mixing up day of month and day of week
Broken idea:
date.getDay();
With older APIs, this may not mean what you expect. Use clear modern methods:
date.getDayOfMonth();
Comparisons
Here is a comparison of common Java date options:
| Approach | Best for | Good points | Drawbacks |
|---|---|---|---|
LocalDate | A date without a time | Clear, modern, safe API | Needs extra conversion for timestamps |
LocalDateTime | Date and time without time zone | Useful for local schedules | Not a specific instant in time |
ZonedDateTime | Date and time with time zone | Good for real-world timestamps | Slightly more complex |
java.util.Date | Legacy code compatibility | Still found in older libraries | Old API, confusing setters |
SimpleDateFormat | Legacy string parsing | Works in old codebases | Old API, less safe, mutable |
LocalDate vs Date
| Feature | LocalDate | Date |
|---|---|---|
| Represents only a calendar date | Yes | No |
| Modern Java API | Yes | No |
| Easy field access | Yes | Less clear |
| Good for new code | Yes | Usually no |
| Timestamp support built in | No, needs conversion | Yes |
Rule of thumb:
- Use
LocalDatefor dates like birthdays, due dates, and calendar entries. - Use timestamps or
Instantwhen you need an exact moment in time. - Use
Dateonly when dealing with old APIs.
Cheat Sheet
// Parse "January 2, 2010"
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse("January 2, 2010", formatter);
Pattern letters:
MMMM= full month name (January)MMM= short month name (Jan)d= day of month (2)dd= day of month with leading zero (02)yyyy= 4-digit year (2010)
Extract values:
int year = date.getYear();
int month = date.getMonthValue();
int day = date.getDayOfMonth();
Convert to timestamp in milliseconds:
long millis = date.atStartOfDay(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
Legacy parsing:
SimpleDateFormat formatter = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
Date date = formatter.parse("January 2, 2010");
long millis = date.getTime();
Rules to remember:
- Prefer
java.timeover oldDateAPIs. - Use
Locale.ENGLISHwhen parsing English month names. LocalDatehas no time zone.- Do not use old
Date#setMonth()andDate#setYear()in new code.
FAQ
How do I parse January 2, 2010 in Java?
Use LocalDate.parse() with a DateTimeFormatter pattern of "MMMM d, yyyy" and Locale.ENGLISH.
Should I use Date or LocalDate in Java?
For new code, use LocalDate if you only need a calendar date. Use Date only for legacy compatibility.
Why does Java need Locale.ENGLISH here?
Because January is an English month name. Without the correct locale, parsing may fail on systems using another language.
How do I get the month, day, and year as integers?
Use:
int month = date.getMonthValue();
int day = date.getDayOfMonth();
int year = date.getYear();
How do I convert a parsed date to milliseconds?
If you have a LocalDate, convert it to the start of the day in a time zone, then get epoch milliseconds.
What is wrong with Date#setMonth() and Date#setYear()?
They belong to the old date API and are confusing, easy to misuse, and not recommended for modern Java code.
Can I still use SimpleDateFormat?
Yes, especially in older codebases, but for new development java.time is the better choice.
Mini Project
Description
Build a small Java utility that reads date strings like "January 2, 2010", parses them into LocalDate, prints the year, month, and day, and then converts the date to epoch milliseconds at the start of the day. This demonstrates the full workflow of parsing, extracting fields, and converting to a machine-friendly time value.
Goal
Create a reusable Java program that safely parses a human-readable date string and converts it into structured values and a timestamp.
Requirements
- Accept a date string in the format
Month day, year - Parse the string using the correct formatter pattern
- Print the extracted year, month, and day as integers
- Convert the parsed date to epoch milliseconds
- Handle invalid input with a clear error message
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.