Apache DateUtils truncate for WEEK

10.6k views Asked by At

I'm using Apache commons-lang3 DateUtils.truncate(Calendar calendar, int field) method to 'cut off' unnecessary fields of a Calendar object. Now when the field parameter gets the value of Calendar.WEEK_OF_MONTH, it throws a

java.lang.IllegalArgumentException: The field 4 is not supported

The truncate() method's documentation says:

/**
 * <p>Truncates a date, leaving the field specified as the most
 * significant field.</p>
 *
 * <p>For example, if you had the date-time of 28 Mar 2002
 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
 * 2002 13:00:00.000.  If this was passed with MONTH, it would
 * return 1 Mar 2002 0:00:00.000.</p>
 * 
 * @param date  the date to work with, not null
 * @param field  the field from {@code Calendar} or <code>SEMI_MONTH</code>
 * @return the different truncated date, not null
 * @throws IllegalArgumentException if the date is <code>null</code>
 * @throws ArithmeticException if the year is over 280 million
 */

So I assume this should work, but it clearly doesn't. Is there a way to truncate dates to the week's first day using DateUtils?


UPDATE:

I looked up in the source code and found out that the modify() method (tuncate() uses this internally), iterates through a bunch of predefined fields to find the given parameter. Now these fields are:

private static final int[][] fields = {
        {Calendar.MILLISECOND},
        {Calendar.SECOND},
        {Calendar.MINUTE},
        {Calendar.HOUR_OF_DAY, Calendar.HOUR},
        {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM 
            /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
        },
        {Calendar.MONTH, DateUtils.SEMI_MONTH},
        {Calendar.YEAR},
        {Calendar.ERA}};

As one can see, there is nothing related to Calendar's WEEK-ish fields, so I guess I have to do this manually... Any other thoughts/recommendations are welcome!

2

There are 2 answers

3
Duncan Jones On BEST ANSWER

It's not really possible to truncate by a week in a sensible fashion. Consider the following date:

2014-11-01 12:01:55

2014-11-01 12:01:00 // truncate minute
2014-11-01 00:00:00 // truncate day
2014-11-00 00:00:00 // truncate month

The original date is a Saturday. So what does week truncation mean in that case? Should we truncate to the previous Monday? If so, that would be:

2014-10-27 00:00:00 // truncate week?

That doesn't seem right to me. We've changed the month in this case; sometimes even the year would change. If you can think of a sensible way to describe this (and some use cases), please file an issue and we'll take a look at it. But it strikes me as a field that makes no sense for truncation.

You may find some ideas for your original problem here: Retrieve current week's Monday's date

0
Basil Bourque On

tl;dr

LocalDate.now( 
    ZoneId.of( "Africa/Tunis" )
).with( 
    TemporalAdjuster.previousOrSame​( DayOfWeek.MONDAY )
)

java.time

No need for an external library like DateUtils. Use the java.time classes built into Java 8 and later.

Sounds like your real question is how to get the first day of the week for a particular date.

Time zone

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter pseudo-zones such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;

The LocalDate class represents a date-only value without time-of-day and without time zone.

LocalDate today = LocalDate.now( z );

To get the first day of the week for that date, we must define the first day of the week. That definition varies by culture. In the United States, we usually mean Sunday. Much of the rest of the world means Monday. Which ever it is for your users, specify with a DayOfWeek enum object.

To move from our date to that date, use a TemporalAdjuster implementation found in TemporalAdjusters class.

LocalDate firstOfWeek = today.with( 
    TemporalAdjuster.previousOrSame​( DayOfWeek.MONDAY ) 
) ;