188

I have a LocalDate which needs to get the first and last day of the month. How do I do that?

eg. 13/2/2014 I need to get 1/2/2014 and 28/2/2014 in LocalDate formats.

Using threeten LocalDate class.

1
  • 4
    Use: LocalDate start = YearMonth.now().atDay(1); LocalDate end = YearMonth.now().atEndOfMonth(); OR: LocalDate startDay = Year.of(2020).atMonth(11).atDay(1); LocalDate endDay = Year.of(2020).atMonth(11).atEndOfMonth(); Commented Nov 17, 2020 at 16:59

13 Answers 13

272

Just use withDayOfMonth, and lengthOfMonth():

LocalDate initial = LocalDate.of(2014, 2, 13);
LocalDate start = initial.withDayOfMonth(1);
LocalDate end = initial.withDayOfMonth(initial.getMonth().length(initial.isLeapYear()));
1
  • 6
    FYI see other answers
    – assylias
    Commented Apr 8, 2014 at 6:51
220

The API was designed to support a solution that matches closely to business requirements

import static java.time.temporal.TemporalAdjusters.*;

LocalDate initial = LocalDate.of(2014, 2, 13);
LocalDate start = initial.with(firstDayOfMonth());
LocalDate end = initial.with(lastDayOfMonth());

However, Jon's solutions are also fine.

1
  • 14
    Going with this one, uses the API resources specifically made to handle this particular problem. Commented Jul 11, 2017 at 16:53
162

YearMonth

For completeness, and more elegant in my opinion, see this use of YearMonth class.

YearMonth month = YearMonth.from(date);
LocalDate start = month.atDay(1);
LocalDate end   = month.atEndOfMonth();

For the first & last day of the current month, this becomes:

LocalDate start = YearMonth.now().atDay(1);
LocalDate end   = YearMonth.now().atEndOfMonth();
6
  • 18
    Best solution of all. Commented Jun 20, 2018 at 14:37
  • Extra info: YearMonth yearMonth = YearMonth.parse("202004",DateTimeFormatter.ofPattern("yyyyMM"));
    – egemen
    Commented Jan 7, 2020 at 8:12
  • what are the advantages of it compared to LocalDate with method? Commented Mar 12, 2020 at 12:10
  • 1
    @AndrewBloom you don't need to use a static function to get the last day of the month, and at least in the second example, you don't need to have a LocalDate instance to start with.
    – herman
    Commented Mar 15, 2020 at 14:52
  • is there something similar for getting the first/last day of the week?
    – DennisVA
    Commented Sep 22, 2021 at 20:11
29

Jon Skeets answer is right and has deserved my upvote, just adding this slightly different solution for completeness:

import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;

LocalDate initial = LocalDate.of(2014, 2, 13);
LocalDate start = initial.withDayOfMonth(1);
LocalDate end = initial.with(lastDayOfMonth());
2
  • 4
    Dear downvoter, honestly, I don't understand the downvote because my answer was even one day before that of JodaStephen and pointed to the mainly interesting new part, namely the temporal adjuster for the end of month. That is I have not "copied" the answer from anyone else. Commented May 21, 2018 at 16:04
  • 1
    Great answer! This solution is better because it's recommended in the docs: "...finding the first or last day of the month" Commented May 24, 2020 at 20:04
10
 LocalDate monthstart = LocalDate.of(year,month,1);
 LocalDate monthend = monthstart.plusDays(monthstart.lengthOfMonth()-1);
1
  • Please describe your answer
    – smilyface
    Commented Jan 17, 2020 at 17:19
7

If anyone comes looking for first day of previous month and last day of previous month:

public static LocalDate firstDayOfPreviousMonth(LocalDate date) {
        return date.minusMonths(1).withDayOfMonth(1);
    }


public static LocalDate lastDayOfPreviousMonth(LocalDate date) {
        return date.withDayOfMonth(1).minusDays(1);
    }
2
  • 1
    Good code, but in Stack Overflow an Answer should address the specifics of the Question. Commented Dec 27, 2018 at 23:08
  • Thank you, I agree. Sometimes we find related code in the thread, as I came looking for this as well. I just put it for such users. Hope that is okay. Thanks. Commented Jan 8, 2019 at 4:09
7
LocalDate endDate = startDate.withDayOfMonth(1).plusMonths(1).minusDays(1);

or

    LocalDate startDate = LocalDate.now();
    System.out.println("startDate: "+startDate);
    
    LocalDate firstDayOfMonth_of_startDate = startDate.withDayOfMonth(1); 
    System.out.println("firstDayOfMonth_of_startDate: "+firstDayOfMonth_of_startDate);
    
    LocalDate firstDayOfNextMonth_of_startDate = firstDayOfMonth_of_startDate.plusMonths(1); 
    System.out.println("firstDayOfNextMonth_of_startDate: "+firstDayOfNextMonth_of_startDate);
    
    LocalDate lastDayOfTheMonth_of_startDate = firstDayOfNextMonth_of_startDate.minusDays(1); 
    System.out.println("lastDayOfTheMonth_of_startDate: "+lastDayOfTheMonth_of_startDate);

    // or everything in one line
    LocalDate endDate = startDate.withDayOfMonth(1).plusMonths(1).minusDays(1);
    System.out.println("endDate: "+endDate);

and the printouts

startDate: 2021-11-05
firstDayOfMonth_of_startDate: 2021-11-01
firstDayOfNextMonth_of_startDate: 2021-12-01
lastDayOfTheMonth_of_startDate: 2021-11-30
endDate: 2021-11-30
1
  • 1
    I updated my response. see above Commented Nov 5, 2021 at 20:58
3

Yet another solution for the last day of the month:

I have written this answer just for learners who want to learn by playing with various options. I do not recommend it for production use.

import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        //Test
        System.out.println(lastDateOfMonth(LocalDate.of(2014, 1, 13)));
        System.out.println(lastDateOfMonth(LocalDate.of(2014, 2, 13)));
        System.out.println(lastDateOfMonth(LocalDate.of(2016, 2, 13)));
        System.out.println(lastDateOfMonth(LocalDate.of(2014, 4, 13)));
    }
    
    static LocalDate lastDateOfMonth(LocalDate date) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .parseDefaulting(ChronoField.DAY_OF_MONTH, 31)
                                .appendPattern("uuuu-MM")
                                .toFormatter(Locale.ENGLISH);
        return LocalDate.parse(YearMonth.from(date).toString(), dtf);
    }
}

Output:

2014-01-31
2014-02-28
2016-02-29
2014-04-30

ONLINE DEMO

How does it work?

The function, YearMonth#toString returns a string in the format, uuuu-MM, the format I have used with the DateTimeFormatterBuilder. I have defaulted the ChronoField.DAY_OF_MONTH to 31, the maximum number of days a month can have, and this works for all months.

Learn more about the modern Date-Time API* from Trail: Date Time.


* 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. Note that Android 8.0 Oreo already provides support for java.time. Check this answer and this answer to learn how to use java.time API with JDBC.

1

if you want to do it only with the LocalDate-class:

LocalDate initial = LocalDate.of(2014, 2, 13);

LocalDate start = LocalDate.of(initial.getYear(), initial.getMonthValue(),1);

// Idea: the last day is the same as the first day of next month minus one day.
LocalDate end = LocalDate.of(initial.getYear(), initial.getMonthValue(), 1).plusMonths(1).minusDays(1);
1

You can try this to avoid indicating custom date and if there is need to display start and end dates of current month:

    LocalDate start = LocalDate.now().minusDays(LocalDate.now().getDayOfMonth()-1);
    LocalDate end = LocalDate.now().minusDays(LocalDate.now().getDayOfMonth()).plusMonths(1);
    System.out.println("Start of month: " + start);
    System.out.println("End of month: " + end);

Result:

>     Start of month: 2019-12-01
>     End of month: 2019-12-30
2
  • 5
    It seems a bit overcomplicated to me. It also doesn’t give the correct result. The last day of this month is 2019-12-31, but your snippet printed 2019-12-30.
    – Anonymous
    Commented Dec 4, 2019 at 14:07
  • The answer itself is wrong, December ends on the 31st and not the 30th. Commented Dec 29, 2022 at 10:26
0

Try this:

LocalDate initial = LocalDate.of(2014, 2, 13);
LocalDate start = initial.withDayOfMonth(1);         
LocalDate end = initial.withDayOfMonth(initial.getMonthOfYear().getLastDayOfMonth(false));
System.out.println(start);
System.out.println(end);

you can find the desire output but need to take care of parameter true/false for getLastDayOfMonth method

that parameter denotes leap year

2
  • There's no need to use getLastDayOfMonth - see my answer for a simpler approach.
    – Jon Skeet
    Commented Mar 6, 2014 at 12:48
  • @Shekhar Rajput The question is about LocalDate from JDK not from JODA! Pay more attention! Commented Dec 29, 2022 at 10:36
0

Just here to show my implementation for @herman solution

ZoneId americaLaPazZone = ZoneId.of("UTC-04:00");

static Date firstDateOfMonth(Date date) {
  LocalDate localDate = convertToLocalDateWithTimezone(date);
  YearMonth baseMonth = YearMonth.from(localDate);
  LocalDateTime initialDate = baseMonth.atDay(firstDayOfMonth).atStartOfDay();
  return Date.from(initialDate.atZone(americaLaPazZone).toInstant());
}

static Date lastDateOfMonth(Date date) {
  LocalDate localDate = convertToLocalDateWithTimezone(date);
  YearMonth baseMonth = YearMonth.from(localDate);
  LocalDateTime lastDate = baseMonth.atEndOfMonth().atTime(23, 59, 59);
  return Date.from(lastDate.atZone(americaLaPazZone).toInstant());
}

static LocalDate convertToLocalDateWithTimezone(Date date) {
  return LocalDateTime.from(date.toInstant().atZone(americaLaPazZone)).toLocalDate();
}
4
  • LocalDateTime is exactly the wrong class to be using here. You are discarding valuable zone/offset information. Commented Sep 21, 2019 at 7:49
  • The Question asks for a date-only value, not the date-with-time values you seek here. And the terrible legacy class Date has nothing to do with the Question, and should generally be avoided. Commented Sep 21, 2019 at 7:52
  • 1
    For La Paz time zone please use the more correct ZoneId.of("America/La_Paz"). For present-day dates it will give the same result, but maybe not for historic dates or dates in a further future.
    – Anonymous
    Commented Sep 22, 2019 at 9:55
  • well, atDay(firstDayOfMonth).atStartOfDay(); and atEndOfMonth().atTime(23, 59, 59) was exactly what i was searching for, thanks.
    – Amr
    Commented Jul 13, 2022 at 4:23
0

use withDayOfMonth. eg. LocalDateTime.now().withDayOfMonth(1) this will give start of the month.

2
  • 1
    Thanks for wanting to contribute. When a LocalDate was asked about, what would be the point of using a LocalDateTime instead? You will be getting a time on the first day of the month, but if one intended the start of that day, you are not getting that.
    – Anonymous
    Commented Aug 4, 2022 at 10:46
  • User was asking for LocalDate and not LocalDateTime please update your answer accordingly
    – L_Cleo
    Commented Aug 8, 2022 at 11:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.