Java LocalDate Tutorial with Examples

LocalDate class represent a date without a time-zone in the ISO-8601 calendar system, such as 1980-04-09, often viewed as year-month-day. This class is immutable and thread-safe.

Creating a LocalDate

We can create a LocalDate in several ways:

LocalDateInitExample.java
import java.time.Clock;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class LocalDateInitExample {

    public static void main(String[] args) {
        LocalDate localDate1 = LocalDate.now();
        System.out.println("LocalDate1: " + localDate1);

        LocalDate localDate2 = LocalDate.now(Clock.systemUTC());
        System.out.println("LocalDate2: " + localDate2);
        
        LocalDate localDate3 = LocalDate.now(ZoneId.systemDefault());
        System.out.println("LocalDate3: " + localDate3);
        
        LocalDate localDate4 = LocalDate.of(1980, 4, 9);
        System.out.println("LocalDate4: " + localDate4);
        
        LocalDate localDate5 = LocalDate.of(1980, Month.APRIL, 9);
        System.out.println("LocalDate5: " + localDate5);
        
        LocalDate localDate6 = LocalDate.ofEpochDay(3629);
        System.out.println("LocalDate6: " + localDate6);
        
        LocalDate localDate7 = LocalDate.ofYearDay(1997, 127);
        System.out.println("LocalDate7: " + localDate7);
        
        LocalDate localDate8 = LocalDate.parse("2018-07-24");
        System.out.println("LocalDate8: " + localDate8);
        
        LocalDate localDate9 = LocalDate.parse("20180724", DateTimeFormatter.BASIC_ISO_DATE);
        System.out.println("LocalDate9: " + localDate9);
    }
}
                    

LocalDate1: 2019-08-21
LocalDate2: 2019-08-20
LocalDate3: 2019-08-21
LocalDate4: 1980-04-09
LocalDate5: 1980-04-09
LocalDate6: 1979-12-09
LocalDate7: 1997-05-07
LocalDate8: 2018-07-24
LocalDate9: 2018-07-24

Since Java 9:

LocalDate localDate = LocalDate.ofInstant(Instant.now(), ZoneId.systemDefault());
System.out.println("LocalDate: " + localDate);
                    

LocalDate: 2019-08-21

LocalDate from and to Epoch

Using LocalDate.ofEpochDay(...) we can obtain an instance of LocalDate from the epoch day count. The other way, we can convert a LocalDate to the number of day from the epoch:

Another method is toEpochSecond(...), which is available since Java 9:

LocalDateFromToEpochExample.java
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneOffset;

public class LocalDateFromToEpochExample {

    public static void main(String[] args) {
        LocalDate localDate = LocalDate.parse("1980-04-09");
        System.out.println("LocalDate                : " + localDate);
        System.out.println("LocalDate.toEpochDay()   : " + localDate.toEpochDay());
        System.out.println("LocalDate.toEpochSecond(): " + localDate.toEpochSecond(LocalTime.MIDNIGHT, ZoneOffset.UTC));
        
        LocalDate copyLocalDate = LocalDate.ofEpochDay(localDate.toEpochDay());
        System.out.println("Copied LocalDate         : " + copyLocalDate);
    }
}
                    

LocalDate                : 1980-04-09
LocalDate.toEpochDay()   : 3751
LocalDate.toEpochSecond(): 324086400
Copied LocalDate         : 1980-04-09

Getting Information from a LocalDate

Following methods can be used to access Date information from a LocalDate:

Method getLong(...) also exists to get the value of specified field from a LocalDate:

LocalDateInfoExample.java
import java.time.LocalDate;
import java.time.temporal.ChronoField;

public class LocalDateInfoExample {
    
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.now();
        System.out.println("LocalDate    : " + localDate);
        System.out.println("DayOfMonth   : " + localDate.getDayOfMonth());
        System.out.println("MonthValue   : " + localDate.getMonthValue());
        System.out.println("Year         : " + localDate.getYear());
        
        System.out.println("DayOfWeek    : " + localDate.getDayOfWeek());
        System.out.println("Month        : " + localDate.getMonth());
        System.out.println("DayOfYear    : " + localDate.getDayOfYear());

        System.out.println("DAY_OF_MONTH : " + localDate.getLong(ChronoField.DAY_OF_MONTH));        
        System.out.println("MONTH_OF_YEAR: " + localDate.getLong(ChronoField.MONTH_OF_YEAR));
        System.out.println("YEAR         : " + localDate.getLong(ChronoField.YEAR));
    }
}
                    

LocalDate    : 2019-08-21
DayOfMonth   : 21
MonthValue   : 8
Year         : 2019
DayOfWeek    : WEDNESDAY
Month        : AUGUST
DayOfYear    : 233
DAY_OF_MONTH : 21
MONTH_OF_YEAR: 8
YEAR         : 2019

Following methods maybe seldom in use:

  • IsoChronology getChronology(): Gets the chronology of this date, which is the ISO calendar system.
  • Era getEra(): Gets the era applicable at this date.
  • boolean isLeapYear(): Checks if the year is a leap year, according to the ISO proleptic calendar system rules.
  • int lengthOfMonth(): Returns the length of the month represented by this date.
  • int lengthOfYear(): Returns the length of the year represented by this date.
System.out.println("Chronology   : " + localDate.getChronology());
System.out.println("Era          : " + localDate.getEra());

System.out.println("LeapYear     : " + localDate.isLeapYear()); // for 2019
System.out.println("LengthOfMonth: " + localDate.lengthOfMonth()); // for AUGUST
System.out.println("LengthOfYear : " + localDate.lengthOfYear()); // for 2019
                    

Chronology   : ISO
Era          : CE
LeapYear     : false
LengthOfMonth: 31
LengthOfYear : 365

Add/Subtract Operations on LocalDate

LocalDate class also has several methods which can be used to do add/subtract operations:

import java.time.Duration;
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;

public class LocalDateAddSubstractExample {

    public static void main(String[] args) {
        LocalDate localDate = LocalDate.parse("1980-04-09");
        System.out.println("LocalDate     : " + localDate);
        
        // Adding/subtracting days
        System.out.println("10 days before: " + localDate.minusDays(10));
        System.out.println("15 days later : " + localDate.plusDays(15));
        
        // Adding/subtracting months
        System.out.println("Minus 4 months: " + localDate.minusMonths(4));
        System.out.println("Plus 5 months : " + localDate.plusMonths(5));
        
        // Adding/subtracting weeks
        System.out.println("Minus 20 weeks: " + localDate.minusWeeks(20));
        System.out.println("Plus 30 weeks : " + localDate.plusWeeks(30));
        
        // Adding/subtracting years
        System.out.println("Minus 12 years: " + localDate.minusYears(12));
        System.out.println("Plus 4 years  : " + localDate.plusYears(4));
        
        // Using DAYS
        System.out.println("30 days before: " + localDate.minus(30, ChronoUnit.DAYS));
        // Using WEEKS
        System.out.println("3 weeks before: " + localDate.minus(3, ChronoUnit.WEEKS));
        // Using MONTHS
        System.out.println("6 months later: " + localDate.plus(6, ChronoUnit.MONTHS));
        // Using YEARS
        System.out.println("2 years later : " + localDate.plus(2, ChronoUnit.YEARS));
        
        // Using TemporalAmount - Period 
        System.out.println("5 years later : " + localDate.plus(Period.ofYears(5)));   
    }
}
                    

LocalDate     : 1980-04-09
10 days before: 1980-03-30
15 days later : 1980-04-24
Minus 4 months: 1979-12-09
Plus 5 months : 1980-09-09
Minus 20 weeks: 1979-11-21
Plus 30 weeks : 1980-11-05
Minus 12 years: 1968-04-09
Plus 4 years  : 1984-04-09
30 days before: 1980-03-10
3 weeks before: 1980-03-19
6 months later: 1980-10-09
2 years later : 1982-04-09
5 years later : 1985-04-09

Note: Using Duration as TemporalAmount

// Using TemporalAmount - Duration System.out.println("60 days before: " + localDate.minus(Duration.ofDays(60)));

producing following error:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds at java.base/java.time.LocalDate.plus(LocalDate.java:1272) at java.base/java.time.LocalDate.minus(LocalDate.java:1448) at java.base/java.time.LocalDate.minus(LocalDate.java:139) at java.base/java.time.Duration.subtractFrom(Duration.java:1137) at java.base/java.time.LocalDate.minus(LocalDate.java:1424) at com.dariawan.datetime.LocalDateAddSubstractExample.main(LocalDateAddSubstractExample.java:80)

It's because temporal is a LocalDate which doesn't have seconds

Duration.java
@Override
public Temporal subtractFrom(Temporal temporal) {
    if (seconds != 0) {
        temporal = temporal.minus(seconds, SECONDS);
    }
    if (nanos != 0) {
        temporal = temporal.minus(nanos, NANOS);
    }
    return temporal;
}
                    

Not sure if this is a bug or expected behavior

Comparing LocalDates

LocalDate class is implementing interface ChronoLocalDate. Following methods can be use to compare two LocalDates:

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

public class LocalDateCompareExample {

    public static void main(String[] args) {
        LocalDate localDate1 = LocalDate.parse("1979-12-09");
        LocalDate localDate2 = LocalDate.parse("1980-04-09");
        LocalDate localDate3 = LocalDate.parse("19791209", DateTimeFormatter.BASIC_ISO_DATE);
        
        System.out.println("LocalDate1 after LocalDate2    : " + localDate1.isAfter(localDate2));
        System.out.println("LocalDate1 before LocalDate2   : " + localDate1.isBefore(localDate2));
        System.out.println("LocalDate1 equal LocalDate3    : " + localDate1.isEqual(localDate3));
        System.out.println("LocalDate3 equal LocalDate3    : " + localDate2.isEqual(localDate3));

        System.out.println("LocalDate1 compareTo LocalDate2: " + localDate1.compareTo(localDate2));
        System.out.println("LocalDate2 compareTo LocalDate1: " + localDate2.compareTo(localDate1));
        System.out.println("LocalDate1 compareTo LocalDate3: " + localDate1.compareTo(localDate3));
        System.out.println("LocalDate3 compareTo LocalDate2: " + localDate3.compareTo(localDate2));
    }
}
                    

LocalDate1 after LocalDate2    : false
LocalDate1 before LocalDate2   : true
LocalDate1 equal LocalDate3    : true
LocalDate3 equal LocalDate3    : false
LocalDate1 compareTo LocalDate2: -1
LocalDate2 compareTo LocalDate1: 1
LocalDate1 compareTo LocalDate3: 0
LocalDate3 compareTo LocalDate2: -1

Supported Field and Unit of a LocalDate

Use isSupported(...) to check if a particular field/unit is supported in a LocalDate:

LocalDate localDate = LocalDate.now();

System.out.println("*** ChronoField ***");
for(ChronoField chronoField : ChronoField.values()){
    System.out.println(chronoField + " is supported:" + localDate.isSupported(chronoField));
}

System.out.println("\n*** ChronoUnit ***");
for(ChronoUnit chronoUnit : ChronoUnit.values()){
    System.out.println(chronoUnit + " is supported:" + localDate.isSupported(chronoUnit));
}
                    

*** ChronoField ***
NanoOfSecond is supported:false
NanoOfDay is supported:false
MicroOfSecond is supported:false
MicroOfDay is supported:false
MilliOfSecond is supported:false
MilliOfDay is supported:false
SecondOfMinute is supported:false
SecondOfDay is supported:false
MinuteOfHour is supported:false
MinuteOfDay is supported:false
HourOfAmPm is supported:false
ClockHourOfAmPm is supported:false
HourOfDay is supported:false
ClockHourOfDay is supported:false
AmPmOfDay is supported:false
DayOfWeek is supported:true
AlignedDayOfWeekInMonth is supported:true
AlignedDayOfWeekInYear is supported:true
DayOfMonth is supported:true
DayOfYear is supported:true
EpochDay is supported:true
AlignedWeekOfMonth is supported:true
AlignedWeekOfYear is supported:true
MonthOfYear is supported:true
ProlepticMonth is supported:true
YearOfEra is supported:true
Year is supported:true
Era is supported:true
InstantSeconds is supported:false
OffsetSeconds is supported:false

*** ChronoUnit ***
Nanos is supported:false
Micros is supported:false
Millis is supported:false
Seconds is supported:false
Minutes is supported:false
Hours is supported:false
HalfDays is supported:false
Days is supported:true
Weeks is supported:true
Months is supported:true
Years is supported:true
Decades is supported:true
Centuries is supported:true
Millennia is supported:true
Eras is supported:true
Forever is supported:false

Convert LocalDate to LocalDateTime

LocalDate class only represent a date without time. To have time information together with date, we need different class. The class that representing a date and the time within that date is LocalDateTime. There are several methods available to convert LocalDate into LocalDateTime:

LocalDateToLocalDateTimeExample.java
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class LocalDateToLocalDateTimeExample {
    
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.parse("1980-04-09");
        
        LocalDateTime localDateTime1 = localDate.atStartOfDay();
        System.out.println("LocalDateTime1: " + localDateTime1);
        
        LocalDateTime localDateTime2 = localDate.atTime(3, 10);
        System.out.println("LocalDateTime2: " + localDateTime2);
        
        LocalDateTime localDateTime3 = localDate.atTime(15, 10, 25);
        System.out.println("LocalDateTime3: " + localDateTime3);
        
        LocalDateTime localDateTime4 = localDate.atTime(15, 10, 25, 123456789);
        System.out.println("LocalDateTime4: " + localDateTime4);
        
        LocalDateTime localDateTime5 = localDate.atTime(LocalTime.NOON);
        System.out.println("LocalDateTime5: " + localDateTime5);
    }
}
                    

LocalDateTime1: 1980-04-09T00:00
LocalDateTime2: 1980-04-09T03:10
LocalDateTime3: 1980-04-09T15:10:25
LocalDateTime4: 1980-04-09T15:10:25.123456789
LocalDateTime5: 1980-04-09T12:00

Getting OffsetDateTime or ZonedDateTime from a LocalDate

Following method is used to create ZonedDateTime from a LocalDate:

  • ZonedDateTime atStartOfDay​(ZoneId zone): Returns a zoned date-time from this date at the earliest valid time according to the rules in the time-zone.

And this method is to create OffsetDateTime from a LocalDate:

LocalDateToZonedOffsetDateTimeExample.java
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class LocalDateToZonedOffsetDateTimeExample {
    
    public static void main(String[] args) {
        LocalDate localDate = LocalDate.parse("1983-07-12");
        
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.of("Asia/Shanghai"));
        System.out.println("ZonedDateTime : " + zonedDateTime);
        
        OffsetDateTime offsetDateTime = localDate.atTime(OffsetTime.of(LocalTime.NOON, ZoneOffset.UTC));
        System.out.println("OffsetDateTime: " + offsetDateTime);
    }
}
                    

ZonedDateTime : 1983-07-12T00:00+08:00[Asia/Shanghai]
OffsetDateTime: 1983-07-12T12:00Z

Conclusion

The LocalDate class represents a local date without time information. If you need both Date and Time information, you should use LocalDateTime instead.