In Joda-Time, set DateTime to start of month

38,492

Solution 1

Midnight at the start of the first day of the current month is given by:

// first midnight in this month
DateMidnight first = new DateMidnight().withDayOfMonth(1);

// last midnight in this month
DateMidnight last = first.plusMonths(1).minusDays(1);

If starting from a java.util.Date, a different DateMidnight constructor is used:

// first midnight in java.util.Date's month
DateMidnight first = new DateMidnight( date ).withDayOfMonth(1);

Joda Time java doc - https://www.joda.org/joda-time/apidocs/overview-summary.html

Solution 2

An alternative way (without taking DateMidnight into account) to get the first day of the month would be to use:

  DateTime firstDayOfMonth = new DateTime().dayOfMonth().withMinimumValue();

Solution 3

First Moment Of The Day

The answer by ngeek is correct, but fails to put the time to the first moment of the day. To adjust the time, append a call to withTimeAtStartOfDay.

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.

org.joda.time.DateTime startOfThisMonth = new org.joda.time.DateTime().dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
org.joda.time.DateTime startofNextMonth = startOfThisMonth.plusMonths( 1 ).dayOfMonth().withMinimumValue().withTimeAtStartOfDay();

System.out.println( "startOfThisMonth: " + startOfThisMonth );
System.out.println( "startofNextMonth: " + startofNextMonth );

When run in Seattle US…

startOfThisMonth: 2013-11-01T00:00:00.000-07:00
startofNextMonth: 2013-12-01T00:00:00.000-08:00

Note the difference in those two lines of console output: -7 vs -8 because of Daylight Saving Time.


Generally one should always specify the time zone rather than rely on default. Omitted here for simplicity. One should add a line like this, and pass the time zone object to the constructors used in example above.

// Time Zone list: http://joda-time.sourceforge.net/timezones.html  (Possibly out-dated, read note on that page)
// UTC time zone (no offset) has a constant, so no need to construct: org.joda.time.DateTimeZone.UTC
org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" );

java.time

The above is correct but outdated. The Joda-Time library is now supplanted by the java.time framework built into Java 8 and later.

The LocalDate represents a date-only value without time-of-day and without time zone. A time zone is crucial in determine a date. For any given moment the date varies by zone around the globe.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );

Use one of the TemporalAdjusters to get first of month.

LocalDate firstOfMonth = today.with( TemporalAdjusters.firstDayOfMonth() );

The LocalDate can generate a ZonedDateTime that represents the first moment of the day.

ZonedDateTime firstMomentOfCurrentMonth = firstOfMonth.atStartOfDay( zoneId );

Solution 4

Oh, I did not see that this was about jodatime. Anyway:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);

int min = c.getActualMinimum(Calendar.DAY_OF_MONTH);
int max = c.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int i = min; i <= max; i++) {
    c.set(Calendar.DAY_OF_MONTH, i);
    System.out.println(c.getTime());
}

Or using commons-lang:

Date min = DateUtils.truncate(date, Calendar.MONTH);
Date max = DateUtils.addMonths(min, 1);
for (Date cur = min; cur.before(max); cur = DateUtils.addDays(cur, 1)) {
    System.out.println(cur);
}

Solution 5

DateMidnight is now deprecated. Instead you can do:

LocalDate firstOfMonth = new LocalDate(date).withDayOfMonth(1);
LocalDate lastOfMonth = firstOfMonth.plusMonths(1).minusDays(1);

If you know the time zone use new LocalDate(date, timeZone) instead for greater accuracy.

You can also do .dayOfMonth().withMinimumValue() instead of .withDayOfMonth(1)

EDIT:

This will give you 12/1/YYYY 00:00 and 12/31/YYYY 00:00. If you rather the last of the month be actually the first of the next month (because you are doing a between clause), then remove the minusDays(1) from the lastOfMonth calculation

Share:
38,492
Maxim Veksler
Author by

Maxim Veksler

Doing healthy things at K Health

Updated on August 21, 2020

Comments

  • Maxim Veksler
    Maxim Veksler almost 4 years

    My API allows library client to pass Date:

    method(java.util.Date date)
    

    Working with Joda-Time, from this date I would like to extract the month and iterate over all days this month contains.

    Now, the passed date is usually new Date() - meaning current instant. My problem actually is setting the new DateMidnight(jdkDate) instance to be at the start of the month.

    Could someone please demonstrates this use case with Joda-Time?

  • Maxim Veksler
    Maxim Veksler over 14 years
    Thanks for the java basic api note. I've learned from this as well.
  • Maxim Veksler
    Maxim Veksler over 14 years
    btw, on that "last" why not: DateMidnight last = first.plusMonths(1).minusDays(1); Same thing,just cleaner.
  • Basil Bourque
    Basil Bourque over 10 years
    This answer was correct, but is now outmoded. Not every day in every time zone has a midnight. Joda-Time 2 added a method withTimeAtStartOfDay to be used in place of the "midnight" features.
  • JustinKSU
    JustinKSU over 9 years
    Although the date would be the first of the month, the time would still be in the middle of the day. Adding .withTimeAtStartOfDay() to the end would resolve this.
  • JustinKSU
    JustinKSU over 9 years
    DateMidnight is now deprecated. From JavaDoc: "The time of midnight does not exist in some time zones where the daylight saving time forward shift skips the midnight hour. Use LocalDate to represent a date without a time zone. Or use DateTime to represent a full date and time, perhaps using DateTime.withTimeAtStartOfDay() to get an instant at the start of a day."
  • JustinKSU
    JustinKSU over 9 years
    @Xylian I guess it depends on the interpretation of the question. For the any day, it will give you midnight on the first of the month and midnight of the last day of the month. If you want midnight of the first day of the next month, just remove the ".minusDays(1) from the second. If you still think my answer is incorrect, please elaborate, because my unit tests say it works.
  • JPhi Denis
    JPhi Denis over 6 years
    you can also add .dayOfMonth().withMaximumValue().hourOfDay().withMaximumValu‌​e() and can add the same with minutes of Hours... to be more precise
  • yash
    yash over 5 years
    DateMidnight is deprecated.