×
Community Blog How Can We Manipulate Time Gracefully in Java?

How Can We Manipulate Time Gracefully in Java?

The author has compiled relevant concepts and tool classes, hoping to help everyone use time more gracefully in the process of code development.

By Qingli

During development, we found that there are many situations where time is needed. For example, we need to record the time of operations and compare times to determine if a product is still valid. In summary, time is a critical aspect that we must always pay attention to in our business development. However, at present, a lot of time tool classes are used in the code of the project. How can time be gracefully manipulated in Java by using Java.util.Date and Java.time.LocalDateTime? The author has sorted out relevant concepts and tool classes, hoping to help everyone use time more gracefully in the process of code development.

Here is a conclusion:

• It is recommended to use the date-time APIs in Java 8, which is much higher than the java.util.Date in terms of security and usability.

• At present, most of the popular time tool classes that encapsulate the Java API are based on the java.util.Date. It is recommended to encapsulate tool classes based on the java.time.* method according to business needs during the development process (a simple implementation is provided at the end of this article).

Storage and Presentation of Time in the Computer

Time is stored as an integer: The essence of time storage in computers is an integer called Epoch Time (timestamp), which calculates the number of seconds elapsed from midnight on January 1, 1970 (Greenwich Mean Time/GMT+00:00) to the present.

In Java programs, timestamps usually use long to represent milliseconds, and they can be obtained through System.currentTimeMillis(). Timestamps are difficult to understand, so we need to convert them into easy-to-read time. For example, 2024-10-7 20:21:59 (which actually refers to local time), and people in different time zones see different local times at the same time. Therefore, when displaying time, it is necessary to include time zone information to pinpoint the corresponding moment accurately.

Time zones are related to the universal time standard:

1

The universal time standard changed in 1972. However, when developing programs, we can ignore the difference between GMT and UTC, because the computer's clock will automatically synchronize time with the time server when connected to the Internet.

Local time is equal to the local time in the time zone we are located (or using), defined by an offset from Coordinated Universal Time (UTC). This offset can be expressed as UTC- or UTC+, followed by the hours and minutes of the offset. For example, GMT+08:00 or UTC+08:00 indicates the eighth time zone in the Eastern Hemisphere. 2024-10-7 20:21:59 UTC+08:00 can accurately locate a moment.

Date API

The JDK has two sets of APIs for handling date/time since version 8.

2

A simple comparison is as follows:

java.util.Date java.util.Date.Calendar java.time.LocalDataTime
Thread Safety
Time Offset
Readability Tue Oct 08 00:11:16 CST 2024 has relatively low readability ✖ Not easily readable ✔ yyy-MM.dd'T'HH:mm:ss
Constant Design Need to process the obtained year (+1900) and month (0-11) Need to process the obtained month (0-11) ✔ No additional processing is required, as it conforms to common sense
Time Precision Millisecond precision Millisecond precision Nanosecond precision
Time Zone A specific moment in time No
Formatting Display java.text.SimpleDateFormat Java.time.DateTimeFormatter
Thread Safety ✖ In a multi-threaded environment, each thread maintains an independent SimpleDateFormat object instance or puts the SimpleDateFormat in ThreadLocal. ✔ Immutable object, thread safety, and the singleton cache
Scenarios Date LocalDateTime

java.util

Before JDK 8, Java used the APIs in the java.util package to handle time.

When obtaining the year, month, and day, the Date and Calendar require different conversions => the rules are not unified.

Date

java.util.Date is used to represent an object of date and time. Its implementation is quite simple. (In fact, it stores a long-type timestamp represented in milliseconds. When obtaining the current time through new Date(), it actually gets the timestamp via System.currentTimeMillis() and assigns the value.)

public class Date {
    long fastTime;

    public Date(long date) {
        fastTime = date;
    }

    public long getTime() {
        return fastTime;
    }
}

java.util.Date has limited functions. When using the Date class to obtain a specific year/month/day, attention should be paid to the following: 1900 must be added to the year returned by the getYear(), the months returned by getMonth() are 0-11, which means January to December respectively, so 1 should be added, while the date range returned by the getDate() is 1~31, which cannot be added with 1.

Calendar

Calendar can be used to obtain and set the year, month, day, hour, minute, and second. Compared with Date, its main additional feature is the ability to perform simple date and time offsets. However, the code is rough, the API is not user-friendly, and the performance is not good.

A Calendar object getTime() can obtain a Date object:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        // Obtain the current time:
        Calendar c = Calendar.getInstance();
        int y = c.get(Calendar.YEAR);// The year returned does not need to be converted.
        int m = 1 + c.get(Calendar.MONTH);// The month returned needs to be added by 1.
        int d = c.get(Calendar.DAY_OF_MONTH);
        int w = c.get(Calendar.DAY_OF_WEEK);// Returned
        int hh = c.get(Calendar.HOUR_OF_DAY);
        int mm = c.get(Calendar.MINUTE);
        int ss = c.get(Calendar.SECOND);
        int ms = c.get(Calendar.MILLISECOND);
        System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);
    }
}
import java.text.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        // Current time:
        Calendar c = Calendar.getInstance();
        // Clear all:
        c.clear();
        // Set year, month, day, hour, minute, and second:
        c.set(2019, 10 /* November */, 20, 8, 15, 0);
        // Add 5 days and subtract 2 hours:
        c.add(Calendar.DAY_OF_MONTH, 5);
        c.add(Calendar.HOUR_OF_DAY, -2);
        // Display time:
        var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = c.getTime();
        System.out.println(sdf.format(d));
        // 2019-11-25 6:15:00
    }
}

TimeZone

Compared with Date, Calendar provides the function of time zone conversion. The time zone is represented by a TimeZone object.

The unique identifier of a time zone is an ID represented by a string. This ID is also used as a parameter to obtain the specified TimeZone object. The GMT+09:00 and Asia/Shanghai are both valid time zone IDs. All IDs supported by the system can be obtained through the TimeZone.getAvailableIDs().

import java.text.*;
import java.util.*;

public class learnTime {
    public static void main(String[] args) {
        // Current time:
        Calendar c = Calendar.getInstance();
        // Clear all fields:
        c.clear();
        // Set to the Beijing time zone:
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // Set year, month, day, hour, minute, and second:
        c.set(2024, 9 /* October */, 10, 8, 15, 0);
        // Display time:
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        System.out.println(sdf.format(c.getTime()));
        // 2024-10-09 20:15:00
    }
}

java.text.SimpleDateFormat

Using Date and SimpleDateFormat for parsing dates:

// SimpleDateFormat threads are not safe; a new instance must be created each time it is used. Define the string format for parsing at the beginning.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

// Parse the specified string into a Date.
Date date = format.parse("2024-10-07 16:10:22");

// Format a Date into a String.
String str = format.format(date);

As SimpleDateFormat threads are not safe, ThreadLocalCache is used to improve performance, as shown below:

static final ThreadLocal<SimpleDateFormat> SIMPLE_DATE_FORMAT_LOCAL 
    = ThreadLocal.withInitial(
         () -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
);

Java.time.*

The open-source community has developed a date class called Joda, which has a clear API and good performance. It was submitted as JSR-310 and became part of the JDK base library in Java 8.

  • Local date and time: LocalDateTime, LocalDate, and LocalTime.

    • As they do not have a time zone, they cannot be converted to timestamps.
  • Date and time with time zone: ZonedDateTime.
  • Instant in time: Instant.
  • Time zone: ZoneId, and ZoneOffset.
  • Time duration: Duration.

As well as a new set of formatting types, DateTimeFormatter designed to replace SimpleDateFormat.

LocalDate/LocalTime/LocalDateTime

  • By default, it strictly prints dates and times according to the ISO 8601 standard (the separator between date and time is T).

    • Date: yyyy-MM-dd; Time: HH:mm:ss.
    • Date and time: yyyy-MM-dd'T'HH:mm:ss.
  • You can parse simple formats to obtain types:
LocalDateTime localDayTime=LocalDateTime.of(2024, 10, 07, 8, 15, 0);
LocalDate localDay=LocalDate.of(2024, 10, 07); 
LocalTime localTime=LocalTime.parse("08:15:07");
  • There is a very simple chain call to add and subtract the date and time, and the time is transformed by plusXxx()/minusXxx():
public class learnTime {
    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2024, 10, 10, 20, 30, 59);
        System.out.println(dt);
        // Add 5 days and subtract 3 hours: 2024-10-10T20:30:59
        LocalDateTime dt2 = dt.plusDays(5).minusHours(3);
        System.out.println(dt2); // 2024-10-15T17:30:59
        // Subtract 1 month:
        LocalDateTime dt3 = dt2.minusMonths(1); //2024-09-15T17:30:59
        System.out.println(dt3); // 2019-09-30T17:30:59
    }
}
  • Use withXxx() to adjust the date and time. For example, adjust the month to:September dataLocalTime.withMonth(9)
  • Complex operations: obtain special times

    • Use with and TemporalAdjusters to find special times (the first day of the current month).
public class Main {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();

        // Obtain the time at 0:00 on the first day of the current month:
        System.out.println("0:00 on the first day of the current month"+now.withDayOfMonth(1).atStartOfDay());
        // Obtain the first day of the current month
        System.out.println("First day of the current month:"+now.with(TemporalAdjusters.firstDayOfMonth()));
        // Obtain the first day of the next month
        System.out.println("First day of the next month:"+now.with(TemporalAdjusters.firstDayOfNextMonth()));
        // Obtain the first day of the next year
        System.out.println("First day of the next year:"+now.with(TemporalAdjusters.firstDayOfNextYear()));
        // Obtain the first day of the current year
        System.out.println("First day of the current year:"+now.with(TemporalAdjusters.firstDayOfYear()));
        // Obtain the last day of the current month
        System.out.println("Last day of the month:"+now.with(TemporalAdjusters.lastDayOfMonth()));
        // Obtain the last day of the current year
        System.out.println("Last day of the current year:"+now.with(TemporalAdjusters.lastDayOfYear()));
        // Obtain the third Friday of the current month
        System.out.println("Third Friday of the current month:"+now.with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.FRIDAY)));
        // Obtain the previous Monday
        System.out.println("Previous Monday:"+now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)));
        // Obtain the next Sunday
        System.out.println("Next Sunday:"+now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));

    }
}
  • The comparison can be made using isBefore() and isAfter().

Duration and Period

  • Duration:
  • Based on time values (Instant/LocalDateTime), it indicates the time interval between two instants. It is suitable for processing shorter durations where higher precision is required.

    • Use the between() method to compare the difference between two instants.
    • Use the getSeconds() or getNanosecends() method to obtain the value of the time unit.
    • Obtain specific granularity intervals: ofDays(), ofHours(), ofMillis(), ofMinutes(), ofNanos(), ofSeconds().
    • Create a Duration object from a text, with the format "PnDTnHnMn.nS", such as Duration.parse("P1DT1H10M10.5S").
    • Use the toDays(), toHours(), toMillis(), and toMinutes() methods to convert the Duration object into other time units.
    • Increase or decrease the Duration object by using the plusX() and minusX() methods, where X represents days, hours, millis, minutes, nanos, or seconds.
  • Period is based on a date value that represents the year, month, and day of a period of time:

    • Use the between() method to compare the difference between two dates.
    • Use the getYears(), getMonhs(), and getDays() methods to obtain the specific granularity gap (the returned type is int).
    • Create a Period object from a text in the format "PnYnMnD", such as Period.parse("P2Y3M5D").
    • Increase or decrease using plusX() or minusX() methods, where X represents the date unit.

ZonedDateTime

ZonedDateTime is LocalDateTime plus ZoneId.

  • Common methods of ZonedDateTime for time with time zones:

    • now(): Obtain the ZonedDateTime object for the current time zone.
    • now(ZoneId zone): Obtain a ZonedDateTime object for a specified time zone.
    • getYear, getMonthValue, getDayOfMonth, and so on: Obtain year, month, day, hour, minute, second, and nanosecond.
    • withXxx (time): Methods to modify the time series.
    • minusXxx (time): Methods to decrease the time series.
    • plusXxx (time): Methods to increase the time series.
  • Time zone conversion
import java.time.*;

public class Main {
    public static void main(String[] args) {
        // Obtain the current time in the China time zone:
        ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        // Convert to New York time:
        ZonedDateTime zny = zbj.withZoneSameInstant(ZoneId.of("America/New_York"));
        System.out.println(zbj);
        System.out.println(zny);
    }
}

ZoneId time zone class

The ZoneId class is similar to java.util.TimeZone in functionality.

ZoneId supports two types of initialization formats, one is the format of the time zone offset (based on UTC/Greenwich Mean Time), and the other is the format of the region time zone (eg: Europe/Paris). ZoneId is an abstract class, with the specific logic implemented by its subclasses. ZoneOffset handles the time zone offset format, while ZoneRegion deals with the region-based time zone format:

getAvailableZoneIds(): Obtain all the time zones supported in Java.

systemDefault(): Obtain the system's default time zone.

of(String zoneId): Obtain a specific time zone.

Format Description Example
Z,GMT,UTC,UT Greenwich Mean Time, which is 8 hours behind China Zoneld.of(“Z”);
+h +hh +hh:mm -hh:mm +hhmm -hhmm +hh:mm:ss -hh:mm:ss +hhmmss -hhmmss Indicate the offset from Greenwich Mean Time; China uses +8 Zoneld.of("+8");
Prefix: UTC+, UTC-, GMT+, GMT-, UT+ UT-. Suffix: +h +hh +hh:mm -hh:mm... Indicate the offset from Greenwich Mean Time Zoneld.of("UTC+8");
Asia/Aden, America/Cuiaba, Etc/GMT+9, Etc/GMT+8, Africa/Nairobi, America/Marigot.. Region notation, these IDs must be included in the getAvailableZonelds collection, otherwise, an exception will be prompted. Zoneld.of(“Asia/shanghai”);

Instant

A specific moment/timestamp on the timeline

You can obtain the instant time by obtaining the instant object. The time consists of two parts: the total number of seconds from 1970-01-01 00:00:00 to this moment and the number of nanoseconds that are less than one second.

• Purpose: It can be used to record the execution time of code or the time point of a user's operation on a specific event.

• The traditional Date class can only be precise to milliseconds and is a mutable object.

• The new Instant class is an immutable object that can be precise to nanoseconds. It is recommended that you use Instant instead of Date.

// 1. Create an Instant object to obtain the current time information
Instant now = Instant.now(); // Immutable object
// 2. Obtain the total number of seconds
long second = now.getEpochSecond();
system.out.println(second) ;
// 3. Obtain the number of nanoseconds less than one second
int nano = now.getNano();
system.out.println(nano) ;

system.out.println(now);
// Perform addition and subtraction 
Instant instant = now.plusNanos(111); // Add nanoseconds by 111

// The purpose of the Instant object: to analyze the performance of the code or to record the time point of the user's operations
Instant now1 = Instant.now();
// Execute code...
Instant now2 = Instant.now();
// Subtracting these two time points can tell you how long the code took to run

DataTimeFormatter

Usage: Pass in a formatted string, and you can specify the local parameter.

import java.time.*;
import java.time.format.*;
import java.util.Locale;

public class Main {
     public static void main(String[] args) {
         ZonedDateTime zdt = ZonedDateTime.now();
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
         System.out.println(formatter.format(zdt));

         DateTimeFormatter zhFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
         System.out.println(zhFormatter.format(zdt));

         DateTimeFormatter usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
         System.out.println(usFormatter.format(zdt));

         //2024-10-08T00:25 GMT+08:00
         //Tue, October/08/2024 00:25
         //Tue, October/08/2024 00:25
}
}

Conversion

For reference on conversion between old and new APIs: https://blog.csdn.net/qq_31635851/article/details/120150588

Conversion between LocalTimeTime and Date:

LocalDateTime does not include a time zone, while <font style="background-color:rgb(249, 242, 244);">Date</font> represents a specific moment in time with millisecond precision.

To convert from <font style="background-color:rgb(249, 242, 244);">LocalDateTime</font> to <font style="background-color:rgb(249, 242, 244);">Date</font>, a time zone must be provided.

// Convert LocalDateTime to Date
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
Date date = Date.from(zonedDateTime.toInstant());
// Convert Date to LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();

Database mapping changes

  • Mapping java.util.Date to the database: <arg column="gmt_create" jdbcType="TIMESTAMP" javaType="java.util.Date"/>
  • Mapping java.time.* to the database: <arg column="gmt_create" jdbcType="TIMESTAMP" javaType="java.time.LocalDateTime"/>

    • MyBatis 3.5.0 and later support for LocalDateTime and other java.time.* classes are included out-of-the-box with type handlers like LocalDateTimeTypeHandler. No additional configuration is required.
    • Older versions of MyBatis may return errors and require additional dependencies.
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>

Correspondence between time-related jdbcType, javaType, and typeHandler in MyBatis

3

Operating Time-related Tools

Some tools encapsulate basic APIs to facilitate effective processing of time in development.

  • Ant Financial time tool class:com.iwallet.biz.common.util.DateUtil

    • Based on the Java.Util.Date, a wide range of date/time processing methods are provided to meet most needs.
  • org.apache.commons.lang3.time

    • It includes a variety of Java.util.Date-based package tools, and provides a lot of convenient algorithms for manipulating dates and times.

Currently, no public time tool class based on Java.time* package has been found.

In many cases, because existing tool classes do not meet current business needs, it is necessary to implement custom tool classes similar to DateUtil within the project. It is recommended to implement these tool classes based on java.time*.

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class DateUtils {

    // Obtain the current date
    public static LocalDate getCurrentDate() {
        return LocalDate.now();
    }

    // Obtain the current time
    public static LocalTime getCurrentTime() {
        return LocalTime.now();
    }

    // Obtain the current date and time
    public static LocalDateTime getCurrentDateTime() {
        return LocalDateTime.now();
    }

    // Format a date to a string
    public static String formatLocalDate(LocalDate date, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return date.format(formatter);
    }

    // Parse a string to a LocalDate
    public static LocalDate parseLocalDate(String dateStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDate.parse(dateStr, formatter);
    }

    // Add a specified number of days
    public static LocalDate addDays(LocalDate date, long days) {
        return date.plusDays(days);
    }

    // Subtract a specified number of days
    public static LocalDate minusDays(LocalDate date, long days) {
        return date.minusDays(days);
    }

    // Calculate the number of days between two dates
    public static long getDaysBetween(LocalDate startDate, LocalDate endDate) {
        return ChronoUnit.DAYS.between(startDate, endDate);
    }

    // Obtain the first day of the month for a specified date
    public static LocalDate getFirstDayOfMonth(LocalDate date) {
        return date.withDayOfMonth(1);
    }

    // Obtain the last day of the month for a specified date
    public static LocalDate getLastDayOfMonth(LocalDate date) {
        return date.withDayOfMonth(date.lengthOfMonth());
    }

    // Check if two dates are equal
    public static boolean isSameDate(LocalDate date1, LocalDate date2) {
        return date1.isEqual(date2);
    }

    // Check if the date is within a specified range
    public static boolean isDateInRange(LocalDate date, LocalDate startDate, LocalDate endDate) {
        return date.isAfter(startDate) && date.isBefore(endDate);
    }

    // Obtain the day of the week for a specified date
    public static DayOfWeek getDayOfWeek(LocalDate date) {
        return date.getDayOfWeek();
    }

    // Check if a year is a leap year
    public static boolean isLeapYear(int year) {
        return Year.of(year).isLeap();
    }

    // Obtain the number of days in a specified month
    public static int getDaysInMonth(int year, int month) {
        return YearMonth.of(year, month).lengthOfMonth();
    }

    // Obtain the year of a specified date
    public static int getYear(LocalDate date) {
        return date.getYear();
    }

    // Obtain the month of a specified date
    public static int getMonth(LocalDate date) {
        return date.getMonthValue();
    }

    // Obtain the number of days for a specified date
    public static int getDayOfMonth(LocalDate date) {
        return date.getDayOfMonth();
    }

    // Obtain the hours of a specified date and time
    public static int getHour(LocalDateTime dateTime) {
        return dateTime.getHour();
    }

    // Obtain the minutes of a specified date and time
    public static int getMinute(LocalDateTime dateTime) {
        return dateTime.getMinute();
    }

    // Obtain the seconds of a specified date and time
    public static int getSecond(LocalDateTime dateTime) {
        return dateTime.getSecond();
    }

    // Check if a specified date is before the current date
    public static boolean isBefore(LocalDate date) {
        return date.isBefore(LocalDate.now());
    }

    // Check if a specified date is after the current date
    public static boolean isAfter(LocalDate date) {
        return date.isAfter(LocalDate.now());
    }

    // Check if a specified date is before or equal to the current date
    public static boolean isBeforeOrEqual(LocalDate date) {
        return date.isBefore(LocalDate.now()) || date.isEqual(LocalDate.now());
    }

    // Check if a specified date is after or equal to the current date
    public static boolean isAfterOrEqual(LocalDate date) {
        return date.isAfter(LocalDate.now()) || date.isEqual(LocalDate.now());
    }

    // Obtain the age based on a birth date
    public static int getAge(LocalDate birthDate) {
        LocalDate currentDate = LocalDate.now();
        return Period.between(birthDate, currentDate).getYears();
    }

    // Obtain the quarter of a specified date
    public static int getQuarter(LocalDate date) {
        return (date.getMonthValue() - 1) / 3 + 1;
    }

    // Obtain the next working day for a specified date
    public static LocalDate getNextWorkingDay(LocalDate date) {
        do {
            date = date.plusDays(1);
        } while (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY);
        return date;
    }

    // Obtain the previous working day for a specified date
    public static LocalDate getPreviousWorkingDay(LocalDate date) {
        do {
            date = date.minusDays(1);
        } while (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY);
        return date;
    }

    // Obtain the first day of the week (Monday) for a specified date
    public static LocalDate getFirstDayOfWeek(LocalDate date) {
        return date.with(DayOfWeek.MONDAY);
    }

    // Obtain the last day of the week (Sunday) for a specified date
    public static LocalDate getLastDayOfWeek(LocalDate date) {
        return date.with(DayOfWeek.SUNDAY);
    }

    // Obtain the first day of the year for a specified date
    public static LocalDate getFirstDayOfYear(LocalDate date) {
        return date.withDayOfYear(1);
    }

    // Obtain the last day of the year for a specified date
    public static LocalDate getLastDayOfYear(LocalDate date) {
        return date.withDayOfYear(date.lengthOfYear());
    }

    // Obtain the first day of the quarter for a specified date
    public static LocalDate getFirstDayOfQuarter(LocalDate date) {
        int month = (date.getMonthValue() - 1) / 3 * 3 + 1;
        return LocalDate.of(date.getYear(), month, 1);
    }

    // Obtain the last day of the quarter for a specified date
    public static LocalDate getLastDayOfQuarter(LocalDate date) {
        int month = (date.getMonthValue() - 1) / 3 * 3 + 3;
        return LocalDate.of(date.getYear(), month, Month.of(month).maxLength());
    }

    // Check if a specified date is a weekday (Monday to Friday)
    public static boolean isWeekday(LocalDate date) {
        return date.getDayOfWeek() != DayOfWeek.SATURDAY && date.getDayOfWeek() != DayOfWeek.SUNDAY;
    }

    // Check if a specified date is a weekend (Saturday or Sunday)
    public static boolean isWeekend(LocalDate date) {
        return date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY;
    }

    // Obtain the number of weekdays in the month in which a specified date falls
    public static int getWeekdayCountOfMonth(LocalDate date) {
        int weekdayCount = 0;
        LocalDate firstDayOfMonth = getFirstDayOfMonth(date);
        LocalDate lastDayOfMonth = getLastDayOfMonth(date);

        while (!firstDayOfMonth.isAfter(lastDayOfMonth)) {
            if (isWeekday(firstDayOfMonth)) {
                weekdayCount++;
            }
            firstDayOfMonth = firstDayOfMonth.plusDays(1);
        }

        return weekdayCount;
    }

    // Obtain the number of weekend days in the month in which a specified date falls
    public static int getWeekendCountOfMonth(LocalDate date) {
        int weekendCount = 0;
        LocalDate firstDayOfMonth = getFirstDayOfMonth(date);
        LocalDate lastDayOfMonth = getLastDayOfMonth(date);

        while (!firstDayOfMonth.isAfter(lastDayOfMonth)) {
            if (isWeekend(firstDayOfMonth)) {
                weekendCount++;
            }
            firstDayOfMonth = firstDayOfMonth.plusDays(1);
        }

        return weekendCount;
    }

    // Obtain the number of weekdays in the year in which a specified date falls
    public static int getWeekdayCountOfYear(LocalDate date) {
        int weekdayCount = 0;
        LocalDate firstDayOfYear = getFirstDayOfYear(date);
        LocalDate lastDayOfYear = getLastDayOfYear(date);

        while (!firstDayOfYear.isAfter(lastDayOfYear)) {
            if (isWeekday(firstDayOfYear)) {
                weekdayCount++;
            }
            firstDayOfYear = firstDayOfYear.plusDays(1);
        }

        return weekdayCount;
    }

}


Disclaimer: The views expressed herein are for reference only and don't necessarily represent the official views of Alibaba Cloud.

0 1 0
Share on

Alibaba Cloud Community

1,133 posts | 351 followers

You may also like

Comments