Get the week start and end date given a current date and week start

Defining A Week

If you are using date-time objects, you should define a week as up to but not including the first moment of the day after the end of week. As seen in this diagram.

Timeline showing ( >= start of day 1 ) and ( < start of day 8 )

This approach is known as Half-Open. This approach is commonly used for working with spans of time.

The reason is because, logically, that last moment of the day before the new day is infinitely divisible as a fraction of a second. You may think that using ".999" would handle that for milliseconds, but then you'd mistaken when writing for the new java.time.* classes in Java 8 that have nanosecond resolution rather than millisecond. You may think think that using ".999999999" would handle that case, but then you’d be mistaken when handling date-time values from many databases such as Postgres that use microsecond resolution, ".999999".

In the third-party open-source Joda-Time library, this Half-Open logic is how its Interval class works. The beginning is inclusive and the ending is exclusive. This works out nicely. Similarly, calling plusWeeks(1) on a DateTime to add a week to the first moment of a day gives you the first moment of the 8th day later (see example below).

Time Zone

The question and other answers ignores the issue of time zone. If you do not specify, you'll be getting the default time zone. Usually better to specify a time zone, using a proper time zone name (not 3-letter code).

Joda-Time

Avoid the java.util.Date & Calendar classes bundled with Java. They are notoriously troublesome.

Here is some example code using Joda-Time 2.3.

CAVEAT: I have not tested of of the below code thoroughly. Just my first take, a rough draft. May well be flawed.

Standard Week (Monday-Sunday)

The Joda-Time library is built around the ISO 8601 standard. That standard defines the first day of the week as Monday, last day as Sunday.

If that meets your definition of a week, then getting the beginning and ending is easy.

UPDATE As an alternative to the discussion below, see this very clever and very simple one-liner solution by SpaceTrucker.

Simply forcing the day-of-week works because Joda-Time assumes you want:

  • Monday to be before (or same as) today.
  • Sunday to be after (or same as) today.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime now = new DateTime( timeZone );

DateTime weekStart = now.withDayOfWeek( DateTimeConstants.MONDAY ).withTimeAtStartOfDay();
DateTime weekEnd = now.withDayOfWeek(DateTimeConstants.SUNDAY).plusDays( 1 ).withTimeAtStartOfDay();
Interval week = new Interval( weekStart, weekEnd );

Dump to console…

System.out.println( "now: " + now );
System.out.println( "weekStart: " + weekStart );
System.out.println( "weekEnd: " + weekEnd );
System.out.println( "week: " + week );

When run…

now: 2014-01-24T06:29:23.043+01:00
weekStart: 2014-01-20T00:00:00.000+01:00
weekEnd: 2014-01-27T00:00:00.000+01:00
week: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00

To see if a date-time lands inside that interval, call the contains method.

boolean weekContainsDate = week.contains( now );

Non-Standard Week

If that does not meet your definition of a week, you a twist on that code.

DateTimeZone timeZone = DateTimeZone.forID( "America/New_York" );
DateTime now = new DateTime( timeZone );

DateTime weekStart = now.withDayOfWeek( DateTimeConstants.SUNDAY ).withTimeAtStartOfDay();
if ( now.isBefore( weekStart )) {
    // If we got next Sunday, go back one week to last Sunday.
    weekStart = weekStart.minusWeeks( 1 );
}
DateTime weekEnd = weekStart.plusWeeks( 1 );
Interval week = new Interval( weekStart, weekEnd );

Dump to console…

System.out.println( "now: " + now );
System.out.println( "weekStart: " + weekStart );
System.out.println( "weekEnd: " + weekEnd );
System.out.println( "week: " + week );

When run…

now: 2014-01-24T00:54:27.092-05:00
weekStart: 2014-01-19T00:00:00.000-05:00
weekEnd: 2014-01-26T00:00:00.000-05:00
week: 2014-01-19T00:00:00.000-05:00/2014-01-26T00:00:00.000-05:00

First day of week depends on the country. What makes the calculation fragile, is that one may break the year boundary, and the week number (Calendar.WEEK_OF_YEAR). The following would do:

    Calendar currentDate = Calendar.getInstance(Locale.US);
    int firstDayOfWeek = currentDate.getFirstDayOfWeek();

    Calendar startDate = Calendar.getInstance(Locale.US);
    startDate.setTime(currentDate.getTime());
    //while (startDate.get(Calendar.DAY_OF_WEEK) != firstDayOfWeek) {
    //    startDate.add(Calendar.DATE, -1);
    //}
    int days = (startDate.get(Calendar.DAY_OF_WEEK) + 7 - firstDayOfWeek) % 7;
    startDate.add(Calendar.DATE, -days);

    Calendar endDate = Calendar.getInstance(Locale.US);
    endDate.setTime(startDate.getTime());
    endDate.add(Calendar.DATE, 6);

One bug in Calendar breaks your code, clone, seems to simply give the identical object, hence at the end you have identical dates. (Java 7 at least).


 DateTime sDateTime = new DateTime(startDate); // My calendar start date
 DateTime eDateTime = new DateTime(date); // the date for the week to be determined

 Interval interval = new Interval(sDateTime, sDateTime.plusWeeks(1));
 while(!interval.contains(eDateTime))
 {
    interval = new Interval(interval.getEnd(), interval.getEnd().plusWeeks(1));
 }
 return interval;