184

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.

tostao
  • 2,803
  • 4
  • 38
  • 61
user1746050
  • 2,415
  • 5
  • 20
  • 26
  • 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(); – Wedson Quintanilha da Silva Nov 17 '20 at 16:59

13 Answers13

267

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()));
Shedrack
  • 656
  • 7
  • 22
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
214

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.

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
156

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();
herman
  • 11,740
  • 5
  • 47
  • 58
  • 18
    Best solution of all. – Agustí Sánchez Jun 20 '18 at 14:37
  • Extra info: YearMonth yearMonth = YearMonth.parse("202004",DateTimeFormatter.ofPattern("yyyyMM")); – egemen Jan 07 '20 at 08:12
  • what are the advantages of it compared to `LocalDate` `with` method? – AndrewBloom Mar 12 '20 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 Mar 15 '20 at 14:52
  • is there something similar for getting the first/last day of the week? – DennisVA Sep 22 '21 at 20:11
  • @DennisVA if your week is Monday-to-Sunday, first day is `date.with(previousOrSame(MONDAY))` (static import from TemporalAdjusters). Last day is `date.with(nextOrSame(SUNDAY))`. Sorry for the late response. – herman Oct 04 '21 at 15:53
28

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());
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • 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. – Meno Hochschild May 21 '18 at 16:04
  • 1
    Great answer! This solution is better because it's recommended in the [docs](https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html): "...finding the first or last day of the month" – Peter Chaula May 24 '20 at 20:04
10
 LocalDate monthstart = LocalDate.of(year,month,1);
 LocalDate monthend = monthstart.plusDays(monthstart.lengthOfMonth()-1);
dersu
  • 189
  • 1
  • 7
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);
    }
Anil Bhaskar
  • 3,718
  • 4
  • 33
  • 51
  • 1
    Good code, but in Stack Overflow an Answer should address the specifics of the Question. – Basil Bourque Dec 27 '18 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. – Anil Bhaskar Jan 08 '19 at 04: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
Viorel Stolea
  • 521
  • 5
  • 7
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.

Spectric
  • 30,714
  • 6
  • 20
  • 43
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
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);
MrSmith42
  • 9,961
  • 6
  • 38
  • 49
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
VSs
  • 61
  • 4
  • 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. – Ole V.V. Dec 04 '19 at 14:07
  • The answer itself is wrong, December ends on the 31st and not the 30th. – Marcus Voltolim Dec 29 '22 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

Moslem Ben Dhaou
  • 6,897
  • 8
  • 62
  • 93
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();
}
Luis Roberto
  • 375
  • 4
  • 10
  • `LocalDateTime` is exactly the wrong class to be using here. You are discarding valuable zone/offset information. – Basil Bourque Sep 21 '19 at 07: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. – Basil Bourque Sep 21 '19 at 07: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. – Ole V.V. Sep 22 '19 at 09:55
  • well, `atDay(firstDayOfMonth).atStartOfDay();` and `atEndOfMonth().atTime(23, 59, 59)` was exactly what i was searching for, thanks. – Amr Jul 13 '22 at 04:23
0

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

  • 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. – Ole V.V. Aug 04 '22 at 10:46
  • User was asking for LocalDate and not LocalDateTime please update your answer accordingly – L_Cleo Aug 08 '22 at 11:19