How to get Date object from MONTH("MMMM") or YEAR("yyyy") using DateTimeFormatter

885 Views Asked by At

I am new to using DateTimeFormatter package, and same thing we are able to get using SimpleDateFormat.

Date date = new SimpleDateFormat("MMMM").parse(month);//"DECEMBER"
Date date = new SimpleDateFormat("yyyy").parse(year);//"2020"

How to achive this using DateTimeFormatter?

4

There are 4 best solutions below

0
On BEST ANSWER

The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. Let's see them in action:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
    public static void main(String[] args) throws ParseException {
        Date date1 = new SimpleDateFormat("MMMM").parse("DECEMBER");
        System.out.println(date1);
        Date date2 = new SimpleDateFormat("yyyy").parse("2020");
        System.out.println(date2);
    }
}

Output:

Tue Dec 01 00:00:00 GMT 1970
Wed Jan 01 00:00:00 GMT 2020

I do not need to explain what defaults they are taking. Instead of taking such unexpected defaults, they should have raised an alarm (throw some exception) which would have become helpful to a programmer to react to.

Because of such surprises, it is recommended to stop using them completely and switch to the modern date-time API.

Note: 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.

Using the modern date-time API:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class Main {
    public static void main(String[] args) {
        System.out.println(parse("DECEMBER", "MMMM"));
        System.out.println(parse("2020", "uuuu"));
    }

    static LocalDate parse(String text, String pattern) {
        try {
            return LocalDate.parse(text, DateTimeFormatter.ofPattern(pattern));
        } catch (DateTimeParseException e) {
            System.out.println(e.getMessage());
            // Return some default value
            return LocalDate.MIN;
        }
    }
}

Output:

Text 'DECEMBER' could not be parsed at index 0
-999999999-01-01
Text '2020' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {Year=2020},ISO of type java.time.format.Parsed
-999999999-01-01

So, now you (the programmer) get to know that you have to do something (e.g. use your own defaults) to parse the strings.

Demo:

import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        LocalDate date = parse("DECEMBER", "MMMM");
        Month month = parse("DECEMBER", "MMMM").getMonth();
        System.out.println(date);
        System.out.println(month);

        date = parse("2020", "uuuu");
        System.out.println(date);
        int year = date.getYear();
        System.out.println(year);
        Year objYear = Year.of(year);
        System.out.println(objYear);
    }

    static LocalDate parse(String text, String pattern) {
        LocalDate today = LocalDate.now();

        // Formatter using today's day, month and year as defaults
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                    .parseCaseInsensitive()
                    .appendPattern(pattern)
                    .parseDefaulting(ChronoField.DAY_OF_MONTH, today.getDayOfMonth())
                    .parseDefaulting(ChronoField.MONTH_OF_YEAR, today.getMonthValue())
                    .parseDefaulting(ChronoField.YEAR, today.getYear())
                    .toFormatter(Locale.ENGLISH);

        try {
            return LocalDate.parse(text, formatter);
        } catch (DateTimeParseException e) {
            System.out.println(e.getMessage());
            // Return some default value
            return LocalDate.MIN;
        }
    }
}

Output:

2020-12-15
DECEMBER
2020-12-15
2020
2020

If you do not want to create a date or date-time object, rather, if all you want to do is to parse your string into Month and Year, you can do it simply the following way:

import java.time.Month;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        Month month = new DateTimeFormatterBuilder()
                        .parseCaseInsensitive()
                        .appendPattern("MMMM")
                        .toFormatter(Locale.ENGLISH)
                        .parse("DECEMBER", Month::from);

        System.out.println(month + " | " + month.getDisplayName(TextStyle.SHORT, Locale.ENGLISH) + " | "
                + month.getDisplayName(TextStyle.FULL, Locale.ENGLISH));
        
        Year year = DateTimeFormatter.ofPattern("uuuu").parse("2020", Year::from);
        System.out.println(year);
    }
}

Output:

DECEMBER | Dec | December
2020

Learn more about the modern date-time API at Trail: Date Time.

0
On

check this link https://www.baeldung.com/java-datetimeformatter. you can use custom format as

String europeanDatePattern = "dd.MM.yyyy";
DateTimeFormatter europeanDateFormatter = DateTimeFormatter.ofPattern(europeanDatePattern);
System.out.println(europeanDateFormatter.format(LocalDate.of(2016, 7, 31)))
0
On

DateTimeFormatter not supporting with util.Date class, here you need to use LocalDate class. You can't parse only with month or year, you should pass 3 values of month, day and year to get Date.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate parsedDate = LocalDate.parse("2020 12 15", formatter);
System.out.print(parsedDate); //2020-12-15
0
On
    String monthString = "December";
    DateTimeFormatter monthFormatter
            = DateTimeFormatter.ofPattern("MMMM", Locale.ENGLISH);
    Month month = monthFormatter.parse(monthString, Month::from);
    System.out.println(month);

Output:

DECEMBER

Year is somewhat simpler. We don’t need a formatter.

    String yearString = "2020";
    Year year = Year.parse(yearString);
    System.out.println(year);

2020

The old Date class despite its name never represented a date. It was a point in time. Yet we commonly used it for a date, a time of day, a month, a year and still more purposes, sometimes also for the point in time that it was. One very confusing consequence was that the Date objects obtained from the code in your question would under rare circumstances incorrectly print as November instead of December and as 2019 instead of 2020. You should no longer use the Date class. It was always poorly designed and is long outdated.

On the other hand java.time, the modern Java date and time API to which DateTimeFormatter belongs, defines a class for each such concept: LocalDate for a date, Month for a month of year, Year for a year, etc. It makes our code clearer about what we are dealing with, which is good. It also requires us to learn about the different classes and think about which one to use each time.

If your month string was in all uppercase, we need to tell the formatter to parse without regard to case:

    String monthString = "DECEMBER";
    DateTimeFormatter monthFormatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("MMMM")
            .toFormatter(Locale.ENGLISH);
    Month month = monthFormatter.parse(monthString, Month::from);

Also when your month name is in English remember to specify an English-speaking locale.