Apache DateUtils truncate day of month

4.3k views Asked by At

I would like to create a DateHelper class and for that I'm using DateUtils from Apache Commons Lang 2.6. I'm having problems understanding the result returned when extract field from a date. Here is my test class which extract the day of month after truncate the date :

    public class DateTest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
//      Date date = createDate(2000, 1, 2, 3, 4, 5, 6);

        Calendar calendar = createEmptyUTCCalendar();
        calendar.set(Calendar.YEAR, 2000);
        calendar.set(Calendar.MONTH, 0); // january
        calendar.set(Calendar.DAY_OF_MONTH, 2);
        calendar.set(Calendar.HOUR_OF_DAY, 3);
        calendar.set(Calendar.MINUTE, 4);
        calendar.set(Calendar.SECOND, 5);
        calendar.set(Calendar.MILLISECOND, 6);

        Date date = calendar.getTime();
    System.out.println("Input date\n" + date);

    // Truncate from day of month.
    Date dateTruncate = getDatePart(date);
    System.out.println("Truncate the date\n" + dateTruncate);

    System.out.println("\n*** Extract day of month ***");
    // Extract the field day of month from the truncated date.
    int fieldDayOfMonth = getField(dateTruncate, Calendar.DAY_OF_MONTH);
    System.out.println("Expected result is 2\nActual result is " + fieldDayOfMonth);

        assert fieldDayOfMonth == 2;
    }

     public static int getField(Date date, int calendarField) {
        Calendar calendar = createEmptyUTCCalendar();
        calendar.setTime(date);
        int value = calendar.get(calendarField);
        if (calendarField == Calendar.MONTH) {
            value++;
        }
        return value;
    }

    public static Date getDatePart(Date date) {
        return DateUtils.truncate(date, Calendar.DAY_OF_MONTH);
    }

    private static Calendar createEmptyUTCCalendar() {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
        return calendar;
    }
}

I expect the result of extracting the field Calendar.DAY_OF_MONTH to be 2 but I got 1.

Input date
Sun Jan 02 04:04:05 CET 2000
Truncate the date
Sun Jan 02 00:00:00 CET 2000

*** Extract day of month ***
Expected result is 2
Actual result is 1
2

There are 2 answers

0
Basil Bourque On

tl;dr

LocalDate.of( 2000 , Month.JANUARY , 2 )
         .getDayOfMonth() 

2

java.time

You can just use Java now, no need for Apache DateUtils. And truncation is the wrong way to think about it; just interrogate for the day-of-month property.

Specify your date using LocalDate class. Note that java.time uses sane month numbering, 1-12 for January to December.

LocalDate ld = LocalDate.of( 2000 , 1 , 2 ) ;  // January 2, 2000.

Or use the Month enum.

LocalDate ld = LocalDate.of( 2000 , Month.JANUARY , 2 ) ;  // January 2, 2000.

2000-01-02

Interrogate for day-of-month. You can call getDayOfMonth on a LocalDate, OffsetDateTime, and ZonedDateTime.

int dayOfMonth = ld.getDayOfMonth​() ;

2

If receiving a Calendar object, it is likely a GregorianCalendar. If so, you can easily convert to java.time classes.

if( myCalendar instanceOf GregorianCalendar ) {
    GregorianCalendar gc = ( GregorianCalendar ) myCalendar ;  // Cast.
    ZonedDateTime zdt = gc.toZonedDateTime() ;  // Convert from legacy class to modern class.
    int dayOfMonth = zdt.getDayOfMonth​() ;
} 

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

1
jjlema On

It seems that the thing is on the timezones. Your calendar is on UTC and your date on your local zone, if you avoid the line:

calendar.setTimeZone(TimeZone.getTimeZone("UTC"));

the thing should work.

When you pass calendar to Date, the date object gets default time zone CET in your case. Then you truncate and pass again to a UTC calendar, and due to the diffenrence between CET and UTC you day is the previous one.