How do I use atDate() method of Java Date-Time API?

The atDate() method is a part of LocalTime class in the Java Date-Time API. This method combines this time with a date to create an instance of LocalDateTime.

Here’s an example:

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class AtDateExample {
    public static void main(String[] args) {
        // Create a LocalTime instance
        LocalTime time = LocalTime.of(14, 20);

        // Create a LocalDate instance
        LocalDate date = LocalDate.of(2023, 1, 23);

        // Using atDate to combine time and date into a LocalDateTime
        LocalDateTime dateTime = time.atDate(date);

        System.out.println(dateTime);
    }
}

Output:

2023-01-23T14:20

In this example, a LocalTime and a LocalDate are combined into a LocalDateTime using the atDate() method. This method is useful when you have a LocalTime instance and want to combine it with a date. It’s in some sense a converse operation to LocalDate‘s atTime().

How do I use atTime() method of Java Date-Time API?

The atTime() method belongs to the LocalDate class in the Java Date-Time API, not the Date class. This method combines this date with a time to create a LocalDateTime.

Here’s an example:

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class AtTimeExample {
    public static void main(String[] args) {
        // Create a LocalDate instance
        LocalDate date = LocalDate.of(2023, 1, 23);

        // Create a LocalTime instance
        // 24-hour clocks
        LocalTime time = LocalTime.of(13, 45);

        // Use atTime() to combine date and time into a LocalDateTime
        LocalDateTime dateTime = date.atTime(time);

        System.out.println(dateTime);
    }
}

Output:

2023-01-23T13:45

In this example, a LocalDate and a LocalTime are combined into a LocalDateTime using the atTime() method.

The LocalDate class also has an overloaded atTime method that takes the hour and minute directly, instead of a LocalTime instance.

Here’s an example where we set 14 hours and 30 minutes directly.

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;

public class AtTimeOtherExample {
    public static void main(String[] args) {
        // Create a LocalDate instance
        LocalDate date = LocalDate.of(2023, 1, 23);

        // Use atTime() to combine date and hour and minute into a
        // LocalDateTime
        LocalDateTime dateTime = date.atTime(14, 30);

        System.out.println(dateTime);
    }
}

Output:

2023-01-23T14:30

In this example, 14:30 (in 24-hour clock) is directly passed into atTime. There is another version of atTime() that takes hrs, min, and sec. That would look like this:

// include seconds
LocalDateTime dateTime = date.atTime(14, 30, 20);
// include nano seconds
LocalDateTime dateTime = date.atTime(14, 30, 20, 200); 

These are all the overloaded versions of atTime() in LocalDate.

Remember, LocalDate, LocalTime, LocalDateTime and others from Java Date-Time API are designed to replace the old Date and Calendar classes from java.util package. They are more consistent, easier to understand and use.

How do I iterate through date range in Java?

The following code snippet shows you how to iterate through a range of dates in Java. We use the Java Date Time API. We do increment and decrement iteration using a simple for loop.

Here are the steps:

  • We declare the start and end date of the loop, the dates are instance of java.time.LocalDate.
  • Create a for loop.
  • In the for loop we set the initialization variable the start date.
  • The loop executed if the date is less than end date, using the isBefore() method, otherwise it will be terminated.
  • The date will be incremented by 1 on each loop.
package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.format.TextStyle;
import java.util.Locale;

public class DateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        System.out.println("Start = " + start);
        System.out.println("End   = " + end);
        System.out.println("--------------------");

        for (LocalDate date = start; date.isBefore(end); date = date.plusDays(1)) {
            System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek());
        }

        System.out.println("--------------------");

        for (LocalDate date = end; date.isAfter(start); date = date.minusDays(1)) {
            System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek()
                    .getDisplayName(TextStyle.SHORT, Locale.getDefault()));
        }
    }
}

Running the code snippet gives you the following output:

Start = 2023-10-01
End   = 2023-10-08
--------------------
Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY
--------------------
Date 10/08/23 is Sun
Date 10/07/23 is Sat
Date 10/06/23 is Fri
Date 10/05/23 is Thu
Date 10/04/23 is Wed
Date 10/03/23 is Tue
Date 10/02/23 is Mon

Next, we are going to use while loop.

  • Define the start and end date to loop
  • We increment the start date by 1 day.
  • Execute the loop if the start date is before end date.
package org.kodejava.datetime;

import java.time.LocalDate;

public class WhileDateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1).minusDays(1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        while ((start = start.plusDays(1)).isBefore(end)) {
            System.out.printf("Date %tD is %s%n", start, start.getDayOfWeek());
        }
    }
}

The result of the code snippet above is:

Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY

To use the Java stream, we can do it like the following code snippet:

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.stream.Stream;

public class StreamDateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        Stream.iterate(start, date -> date.plusDays(1))
                .limit(ChronoUnit.DAYS.between(start, end))
                .forEach(date -> {
                    System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek());
                });
    }
}

The result of the code snippet above is:

Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY

From Java 9 we can use LocalDate.datesUntil() method. It will iterate from the date to the specified end date by increment step of 1 day or the specified increment of Period.

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.Period;

public class DatesUntilDateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        start.datesUntil(end).forEach(date -> {
            System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek());
        });

        start.datesUntil(end, Period.ofDays(2)).forEach(System.out::println);
    }
}

Running the code snippet produces the following result:

Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY
2023-10-01
2023-10-03
2023-10-05
2023-10-07

How do I convert datetime string with optional part to a date object?

Since JDK 8, we can create a datetime formatter / parser pattern that can have optional sections. When parsing a datetime string that contains optional values, for example, a date without time part or a datetime without second part, we can create a parsing pattern wrapped within the [] symbols. The [ character is the optional section start symbol, and the ] character is the optional section end symbol. The pattern inside this symbol will be considered as an optional value.

We can use the java.time.format.DateTimeFormatter class to parse the string of datetime or format the datetime object, and use it with the new Java time API classes such as java.time.LocalDate or java.time.LocalDateTime to convert the string into respective LocalDate or LocalDateTime object as show in the code snippet below.

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class DateTimeParseOptionalParts {
    public static final String OPT_TIME_PATTERN = "yyyy-MM-dd[ HH:mm[:ss]]";
    public static final String OPT_SECOND_PATTERN = "yyyy-MM-dd HH:mm[:ss]";

    public static void main(String[] args) {
        DateTimeFormatter optTimeFormatter = DateTimeFormatter.ofPattern(OPT_TIME_PATTERN);
        LocalDate date1 = LocalDate.parse("2023-08-28", optTimeFormatter);
        LocalDate date2 = LocalDate.parse("2023-08-28 17:15", optTimeFormatter);
        LocalDate date3 = LocalDate.parse("2023-08-28 17:15:30", optTimeFormatter);
        System.out.println("date1 = " + date1);
        System.out.println("date2 = " + date2);
        System.out.println("date3 = " + date3);

        DateTimeFormatter optSecondFormatter = DateTimeFormatter.ofPattern(OPT_SECOND_PATTERN);
        LocalDateTime datetime1 = LocalDateTime.parse("2023-08-28 17:15", optSecondFormatter);
        LocalDateTime datetime2 = LocalDateTime.parse("2023-08-28 17:15:30", optSecondFormatter);
        System.out.println("datetime1 = " + datetime1);
        System.out.println("datetime2 = " + datetime2);
    }
}

Here are the outputs of the code snippet above:

date1 = 2023-08-28
date2 = 2023-08-28
date3 = 2023-08-28
datetime1 = 2023-08-28T17:15
datetime2 = 2023-08-28T17:15:30

How do I calculate days between two dates excluding weekends and holidays?

The code snippet below shows you a simple way to calculate days between two dates excluding weekends and holidays. As an example, you can use this function for calculating work days. The snippet utilize the java.time API and the Stream API to calculate the value.

What we do in the code below can be described as the following:

  • Create a list of holidays. The dates might be read from a database or a file.
  • Define filter Predicate for holidays.
  • Define filter Predicate for weekends.
  • These predicates will be use for filtering the days between two dates.
  • Define the startDate and the endDate to be calculated.
  • Using Stream.iterate() we iterate the dates, filter it based on the defined predicates.
  • Finally, we get the result as list.
  • The actual days between is the size of the list, workDays.size().
package org.kodejava.datetime;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class DaysBetweenDates {
    public static void main(String[] args) {
        List<LocalDate> holidays = new ArrayList<>();
        holidays.add(LocalDate.of(2022, Month.DECEMBER, 26));
        holidays.add(LocalDate.of(2023, Month.JANUARY, 2));

        Predicate<LocalDate> isHoliday = holidays::contains;
        Predicate<LocalDate> isWeekend = date -> date.getDayOfWeek() == DayOfWeek.SATURDAY
                || date.getDayOfWeek() == DayOfWeek.SUNDAY;

        LocalDate startDate = LocalDate.of(2022, Month.DECEMBER, 23);
        LocalDate endDate = LocalDate.of(2023, Month.JANUARY, 3);
        System.out.println("Start date = " + startDate);
        System.out.println("End date   = " + endDate);

        // Days between startDate inclusive and endDate exclusive
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        System.out.println("Days between = " + daysBetween);

        List<LocalDate> workDays = Stream.iterate(startDate, date -> date.plusDays(1))
                .limit(daysBetween)
                .filter(isHoliday.or(isWeekend).negate())
                .toList();

        long actualDaysBetween = workDays.size();
        System.out.println("Actual days between = " + actualDaysBetween);
    }
}

Running the code snippet above give us the following result:

Start date = 2022-12-23
End date   = 2023-01-03
Days between = 11
Actual days between = 5