diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/DateUtil.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/DateUtil.java new file mode 100644 index 0000000..7dd1607 --- /dev/null +++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/util/DateUtil.java @@ -0,0 +1,311 @@ +package com.klaro.acquirecore.framework.util; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.Objects; + +/** + * Static utility class for date operations migrated from legacy/util_date.c + * Uses java.time.LocalDate and java.time.LocalDateTime for date handling. + */ +public final class DateUtil { + + public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; + public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + public static final String KOREAN_DATE_FORMAT = "yyyy년 MM월 dd일"; + public static final String ISO_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; + + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT); + private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT); + private static final DateTimeFormatter KOREAN_FORMATTER = DateTimeFormatter.ofPattern(KOREAN_DATE_FORMAT); + private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter.ofPattern(ISO_DATE_FORMAT); + + private DateUtil() { + throw new UnsupportedOperationException("Utility class cannot be instantiated"); + } + + /** + * Parses a date string using the default format (yyyy-MM-dd). + * + * @param dateStr the date string to parse + * @return the parsed LocalDate + * @throws DateTimeParseException if the string cannot be parsed + */ + public static LocalDate parseDate(String dateStr) { + Objects.requireNonNull(dateStr, "dateStr must not be null"); + return LocalDate.parse(dateStr, DATE_FORMATTER); + } + + /** + * Parses a date string using the specified format pattern. + * + * @param dateStr the date string to parse + * @param pattern the date format pattern + * @return the parsed LocalDate + * @throws DateTimeParseException if the string cannot be parsed + */ + public static LocalDate parseDate(String dateStr, String pattern) { + Objects.requireNonNull(dateStr, "dateStr must not be null"); + Objects.requireNonNull(pattern, "pattern must not be null"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return LocalDate.parse(dateStr, formatter); + } + + /** + * Parses a datetime string using the default format (yyyy-MM-dd HH:mm:ss). + * + * @param dateTimeStr the datetime string to parse + * @return the parsed LocalDateTime + * @throws DateTimeParseException if the string cannot be parsed + */ + public static LocalDateTime parseDateTime(String dateTimeStr) { + Objects.requireNonNull(dateTimeStr, "dateTimeStr must not be null"); + return LocalDateTime.parse(dateTimeStr, DATETIME_FORMATTER); + } + + /** + * Parses a datetime string using the specified format pattern. + * + * @param dateTimeStr the datetime string to parse + * @param pattern the datetime format pattern + * @return the parsed LocalDateTime + * @throws DateTimeParseException if the string cannot be parsed + */ + public static LocalDateTime parseDateTime(String dateTimeStr, String pattern) { + Objects.requireNonNull(dateTimeStr, "dateTimeStr must not be null"); + Objects.requireNonNull(pattern, "pattern must not be null"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return LocalDateTime.parse(dateTimeStr, formatter); + } + + /** + * Formats a LocalDate using the default format (yyyy-MM-dd). + * + * @param date the date to format + * @return the formatted date string + */ + public static String formatDate(LocalDate date) { + Objects.requireNonNull(date, "date must not be null"); + return date.format(DATE_FORMATTER); + } + + /** + * Formats a LocalDate using the specified format pattern. + * + * @param date the date to format + * @param pattern the format pattern + * @return the formatted date string + */ + public static String formatDate(LocalDate date, String pattern) { + Objects.requireNonNull(date, "date must not be null"); + Objects.requireNonNull(pattern, "pattern must not be null"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return date.format(formatter); + } + + /** + * Formats a LocalDateTime using the default format (yyyy-MM-dd HH:mm:ss). + * + * @param dateTime the datetime to format + * @return the formatted datetime string + */ + public static String formatDateTime(LocalDateTime dateTime) { + Objects.requireNonNull(dateTime, "dateTime must not be null"); + return dateTime.format(DATETIME_FORMATTER); + } + + /** + * Formats a LocalDateTime using the specified format pattern. + * + * @param dateTime the datetime to format + * @param pattern the format pattern + * @return the formatted datetime string + */ + public static String formatDateTime(LocalDateTime dateTime, String pattern) { + Objects.requireNonNull(dateTime, "dateTime must not be null"); + Objects.requireNonNull(pattern, "pattern must not be null"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + return dateTime.format(formatter); + } + + /** + * Formats a LocalDate in Korean date format (yyyy년 MM월 dd일). + * + * @param date the date to format + * @return the formatted Korean date string + */ + public static String formatDateKorean(LocalDate date) { + Objects.requireNonNull(date, "date must not be null"); + return date.format(KOREAN_FORMATTER); + } + + /** + * Calculates the number of days between two dates. + * + * @param startDate the start date + * @param endDate the end date + * @return the number of days between the dates + */ + public static long daysBetween(LocalDate startDate, LocalDate endDate) { + Objects.requireNonNull(startDate, "startDate must not be null"); + Objects.requireNonNull(endDate, "endDate must not be null"); + return ChronoUnit.DAYS.between(startDate, endDate); + } + + /** + * Adds days to a date. + * + * @param date the base date + * @param days the number of days to add (can be negative) + * @return the resulting date + */ + public static LocalDate addDays(LocalDate date, long days) { + Objects.requireNonNull(date, "date must not be null"); + return date.plusDays(days); + } + + /** + * Adds months to a date. + * + * @param date the base date + * @param months the number of months to add (can be negative) + * @return the resulting date + */ + public static LocalDate addMonths(LocalDate date, long months) { + Objects.requireNonNull(date, "date must not be null"); + return date.plusMonths(months); + } + + /** + * Adds years to a date. + * + * @param date the base date + * @param years the number of years to add (can be negative) + * @return the resulting date + */ + public static LocalDate addYears(LocalDate date, long years) { + Objects.requireNonNull(date, "date must not be null"); + return date.plusYears(years); + } + + /** + * Checks if a date is before another date. + * + * @param date the date to check + * @param dateToCompare the date to compare against + * @return true if date is before dateToCompare + */ + public static boolean isBefore(LocalDate date, LocalDate dateToCompare) { + Objects.requireNonNull(date, "date must not be null"); + Objects.requireNonNull(dateToCompare, "dateToCompare must not be null"); + return date.isBefore(dateToCompare); + } + + /** + * Checks if a date is after another date. + * + * @param date the date to check + * @param dateToCompare the date to compare against + * @return true if date is after dateToCompare + */ + public static boolean isAfter(LocalDate date, LocalDate dateToCompare) { + Objects.requireNonNull(date, "date must not be null"); + Objects.requireNonNull(dateToCompare, "dateToCompare must not be null"); + return date.isAfter(dateToCompare); + } + + /** + * Checks if a date is between two other dates (inclusive). + * + * @param date the date to check + * @param startDate the start of the range + * @param endDate the end of the range + * @return true if date is between startDate and endDate (inclusive) + */ + public static boolean isBetween(LocalDate date, LocalDate startDate, LocalDate endDate) { + Objects.requireNonNull(date, "date must not be null"); + Objects.requireNonNull(startDate, "startDate must not be null"); + Objects.requireNonNull(endDate, "endDate must not be null"); + return !date.isBefore(startDate) && !date.isAfter(endDate); + } + + /** + * Gets the start of the day for a given date. + * + * @param date the date + * @return the start of the day as LocalDateTime (00:00:00) + */ + public static LocalDateTime startOfDay(LocalDate date) { + Objects.requireNonNull(date, "date must not be null"); + return date.atStartOfDay(); + } + + /** + * Gets the end of the day for a given date. + * + * @param date the date + * @return the end of the day as LocalDateTime (23:59:59.999999999) + */ + public static LocalDateTime endOfDay(LocalDate date) { + Objects.requireNonNull(date, "date must not be null"); + return date.atTime(23, 59, 59, 999999999); + } + + /** + * Gets today's date. + * + * @return the current date + */ + public static LocalDate today() { + return LocalDate.now(); + } + + /** + * Gets the current datetime. + * + * @return the current datetime + */ + public static LocalDateTime now() { + return LocalDateTime.now(); + } + + /** + * Validates if a string is a valid date in the default format. + * + * @param dateStr the date string to validate + * @return true if valid, false otherwise + */ + public static boolean isValidDate(String dateStr) { + if (dateStr == null || dateStr.isEmpty()) { + return false; + } + try { + parseDate(dateStr); + return true; + } catch (DateTimeParseException e) { + return false; + } + } + + /** + * Validates if a string is a valid date in the specified format. + * + * @param dateStr the date string to validate + * @param pattern the expected format pattern + * @return true if valid, false otherwise + */ + public static boolean isValidDate(String dateStr, String pattern) { + if (dateStr == null || dateStr.isEmpty() || pattern == null) { + return false; + } + try { + parseDate(dateStr, pattern); + return true; + } catch (DateTimeParseException e) { + return false; + } + } +}