If possible I would prefer a joda or non-joda solution for the scenario below
Lets say if my week starts on 02/05/2012 and the given current date is 02/22/2011. I ne
Try this (pseudo-code):
// How many days gone after reference date (a known week-start date)
daysGone = today - referenceDate;
// A new week starts after each 7 days
dayOfWeek = daysGone % 7;
// Now, we know today is which day of the week.
// We can find start & end days of this week with ease
weekStart = today - dayOfWeek;
weekEnd = weekStart + 6;
Now, we can shorten all of this to two lines:
weekStart = today - ((today - referenceDate) % 7);
weekEnd = weekStart + 6;
Note that we subtracted date values like integers to show algorithm. You have to write your java code properly.
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;
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.
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).
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).
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.
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:
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 );
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).