user6863891
user6863891

Reputation:

java: represent Date with optional month and day

I would like to store Date with optional month and day in java. I know of the java.time.LocalYear class to store just the year. Shall I create my own custom class to hold dates with optional month and day or are there any custom library to solve the problem.


public class Date {

  private LocalYear year;
  private int month;
  private int day;

  public Date(LocalYear year) {
   this.year = year;
  } 
  
  public Date(LocalYear year, int month) {
   this.year = year;
   this.month = month;
  }

  public Date(LocalYear year, int month, iny day) {
   this.year = year;
   this.month = month;
   this.day = day;
  }
}

Upvotes: 0

Views: 973

Answers (1)

Anonymous
Anonymous

Reputation: 86324

It’s hard to guide you without knowing your use case. One option is using the TemporalAccessor interface as a common type for dates with and without month and/or day of month and then put either a LocalDate, a YearMonth or a Year into your variable (the last class is just called Year (not LocalYear, though it would have been in line with the naming scheme)). For example:

    List<TemporalAccessor> dates = List.of(
            LocalDate.of(2019, Month.OCTOBER, 3), // full date
            YearMonth.of(2019, Month.NOVEMBER), // no day of month
            Year.of(2020)); // no month or day of month

What can we use this for? One example:

    for (TemporalAccessor ta : dates) {
        System.out.println(ta);
        System.out.println("Year: " + ta.get(ChronoField.YEAR));
        if (ta.isSupported(ChronoField.MONTH_OF_YEAR)) {
            System.out.println("Month: " + ta.get(ChronoField.MONTH_OF_YEAR));
        } else {
            System.out.println("Month: undefined");
        }
        if (ta.isSupported(ChronoField.DAY_OF_MONTH)) {
            System.out.println("Day: " + ta.get(ChronoField.DAY_OF_MONTH));
        } else {
            System.out.println("Day: undefined");
        }
        System.out.println();
    }

This outputs:

2019-10-03
Year: 2019
Month: 10
Day: 3

2019-11
Year: 2019
Month: 11
Day: undefined

2020
Year: 2020
Month: undefined
Day: undefined

Whether or how well it fulfils your requirements I cannot tell.

Using ChronoField constants for access is low-level, so you may want to wrap the TemporalAccessor in a nice class with nice getters. For example:

public class PartialDate {

    private TemporalAccessor date;

    public PartialDate(Year year) {
        date = year;
    }

    public PartialDate(Year year, int month) {
        date = year.atMonth(month);
    }

    public PartialDate(Year year, int month, int day) {
        date = year.atMonth(month).atDay(day);
    }

    public Year getYear() {
        return Year.from(date);
    }

    public OptionalInt getMonthValue() {
        if (date.isSupported(ChronoField.MONTH_OF_YEAR)) {
            return OptionalInt.of(date.get(ChronoField.MONTH_OF_YEAR));
        } else {
            return OptionalInt.empty();
        }
    }

    // A similar getDay method

}

You may extend the class to your needs. Maybe you want constructors that accept a Month enum constant and/or a YearMonth object directly and/or getters that return those types wrapped in Optionals.

Link: Oracle tutorial: Date Time explaining how to use java.time.

Upvotes: 3

Related Questions