1. 程式人生 > >任意時間間隔內某星期幾的所有對應日期

任意時間間隔內某星期幾的所有對應日期

package java8.date;

import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * @author Gu Yuanhua
 * created time 2018/7/5 23:39
 */
class DateTimeUtils {

    /**
     * 一個星期的週期為7天
     */
    private static final int PERIOD = 7;

    /**
     * 列印某年星期幾的所有對應日期
     *
     * @param startDate 某年
     * @param week      星期幾
     */
    static void queryDayOfWeek(LocalDate startDate,
                               LocalDate endDate, String week) {

        // 計算兩個日期間的天數
        long days = ChronoUnit.DAYS.between(startDate, endDate);

        // 開始時間不能晚於結束時間!
        if (days < 0) {
            throw new DateTimeException("開始時間不能晚於結束時間!");
        }

        // 建立一個集合存放所有的星期幾
        List<LocalDate> allWeek;

        if (days < PERIOD) {
            // 時間間隔小於7天
            allWeek = lessThanSevenDays(startDate, days, week);

        } else {
            // 時間間隔大於7天
            allWeek = moreThanSevenDays(startDate, endDate, week);

        }

        // 列印星期幾對應的所有日期
        allWeek.forEach(System.out::println);

    }

    /**
     * 時間間隔大於7天
     *
     * @param startDate 開始日期
     * @param endDate   結束日期
     * @param week      星期幾
     * @return 對應日期集合
     */
    private static List<LocalDate> moreThanSevenDays(LocalDate startDate, LocalDate endDate, String week) {

        // 中文日期轉化英文日期
        String englishWeek = weekFormat(week);

        // 當前日期指標
        LocalDate currentDate = startDate;

        List<LocalDate> weeks = new ArrayList<>();

        // 找到第一個星期幾
        for (int i = 1; i <= PERIOD; i++) {
            if (Objects.equals(englishWeek, currentDate.getDayOfWeek().toString())) {
                // 第一個星期幾放入集合
                weeks.add(currentDate);
                // 當前日期指標指向下一個星期幾
                currentDate=currentDate.plusWeeks(1);
                break;
            }
            currentDate = currentDate.plusDays(1);
        }

        // 找到剩下的所有星期幾
        while (currentDate.getYear () < endDate.getYear () ||
               currentDate.getMonthValue () < endDate.getMonthValue () ||
               currentDate.getDayOfMonth () < endDate.getDayOfMonth ()) {
            // 當前星期幾放入集合
            weeks.add (currentDate);
            // 當前日期指標指向下一個星期幾
            currentDate = currentDate.plusWeeks (1);
        }

        return weeks;
    }

    /**
     * 時間間隔小於7天
     *
     * @param startDate 開始日期
     * @param days      時間間隔
     * @param week      星期幾
     * @return 對應日期集合
     */
    private static List<LocalDate> lessThanSevenDays(LocalDate startDate, long days, String week) {

        // 中文日期轉化英文日期
        String englishWeek = weekFormat(week);

        List<LocalDate> weeks = new ArrayList<>();
        // days可能為0,也就是開始日期等於結束日期,所以需要i<=days
        for (int i = 0; i <= days; i++) {
            // 如果時間間隔內找到這個星期幾
            if (Objects.equals(startDate.getDayOfWeek().toString(), englishWeek)) {
                weeks.add(startDate);
                return weeks;
            }

            startDate = startDate.plusDays(i);
        }
        // 7天時間間隔遍歷後依然沒有找到
        throw new DateTimeException("時間間隔小於7天,無法找到:" + week);
    }

    /**
     * 將中文日期轉化為英文
     *
     * @param week 中文日期
     * @return 英文日期
     */
    private static String weekFormat(String week) {
        switch (week) {
            case "星期一":
                week = "MONDAY";
                break;
            case "星期二":
                week = "TUESDAY";
                break;
            case "星期三":
                week = "WEDNESDAY";
                break;
            case "星期四":
                week = "THURSDAY";
                break;
            case "星期五":
                week = "FRIDAY";
                break;
            case "星期六":
                week = "SATURDAY";
                break;
            case "星期日":
                week = "SUNDAY";
                break;
            default:
                throw new DateTimeException("日期不正確");
        }
        return week;
    }

}

測試程式碼

package java8.date;

import org.junit.Test;
import java.time.LocalDate;

/**
 * @author Gu Yuanhua
 * created time 2018/7/3 22:47
 */
public class LocalDateTimeTest {

    @Test
    public void testLodalDateTime() {

        System.out.println("============開始時間晚於結束時間的測試==============");
        // 開始時間晚於結束時間的測試
        LocalDate startDate = LocalDate.of(2019, 1, 6);
        LocalDate endDate = LocalDate.of(2018, 1, 1);
        DateTimeUtils.queryDayOfWeek(startDate,endDate, "星期二");

        System.out.println("============時間間隔小於7天的測試==============");

        // 時間間隔小於7天的測試
        LocalDate startDate1 = LocalDate.of(2018, 1, 1);
        LocalDate endDate1 = LocalDate.of(2018, 1, 6);
        DateTimeUtils.queryDayOfWeek(startDate1, endDate1, "星期二");

        System.out.println("===========時間間隔大於7天的測試===============");

        // 時間間隔大於7天的測試
        LocalDate startDate2 = LocalDate.of(2018, 6, 6);
        LocalDate endDate2 = LocalDate.of(2019, 6, 6);
        DateTimeUtils.queryDayOfWeek(startDate2, endDate2, "星期二");
    }

}

使用Stream以及Groovy方式

/**
 * 獲取兩個日期間隔的所有日期
 *
 * @param startDate 開始日期
 * @param endDate   結束日期
 * @return 所有日期的集合
 */
static List<LocalDate> queryWeek(LocalDate startDate, LocalDate endDate, String week) {
    String englishWeek = weekFormat (week);
    long days = ChronoUnit.DAYS.between (startDate, endDate);
    if (days < 0) {
    throw new DateTimeException ("開始時間不能晚於結束時間!");
    }
    return Stream.iterate (startDate, date -> date.plusDays (1))
                 .limit (days + 1)        // 總的天數是間隔天數+1
                 .filter (date -> Objects.equals (date.getDayOfWeek ().toString (), englishWeek))
                 .collect (Collectors.toList ());
    }
static def queryWeek(LocalDate startDate, LocalDate endDate, String week) {
        def englishWeek = weekFormat(week)
        long days = ChronoUnit.DAYS.between(startDate, endDate)
        def weeks = []      // 所有星期幾對應日期集合
        def currentDate = startDate     // 當前日期
        if (days < 0) {
            throw new DateTimeException("開始時間不能晚於結束時間!")
        } else {
            (days + 1).times {
                if (currentDate.getDayOfWeek().toString() == englishWeek) {
                    weeks << currentDate
                }
                currentDate = currentDate.plusDays(1) // 更新當前日期
            }
            return weeks
        }
    }

時間複雜度O(n)優化為O(n/7)

/**
 * 獲取兩個日期間隔的所有日期
 *
 * @param startDate 開始日期
 * @param endDate   結束日期
 * @return 所有日期的集合
 */
static List<LocalDate> queryWeek(LocalDate startDate, LocalDate endDate, String week) {
   String englishWeek = weekFormat (week);
   long days = ChronoUnit.DAYS.between (startDate, endDate);
   if (days < 0) {
       throw new DateTimeException ("開始時間不能晚於結束時間!");
    } else {
        LocalDate firstDate = Stream.iterate (startDate, date -> date.plusDays (1))
                                    .filter (date -> Objects.equals (date.getDayOfWeek ().toString (), englishWeek))
                                    .findFirst ()
                                    .get ();
        return Stream.iterate (firstDate, date -> date.plusWeeks (1))
                     .limit (days / 7 + 1)        // 總的天數是間隔天數+1
                     .filter (date -> Objects.equals (date.getDayOfWeek ().toString (), englishWeek))
                     .collect (Collectors.toList ());
    }
}
static def queryWeek(LocalDate startDate, LocalDate endDate, String week) {
        def englishWeek = weekFormat(week)
        long days = ChronoUnit.DAYS.between(startDate, endDate)
        def weeks = []      // 所有星期幾對應日期集合
        def currentDate = startDate     // 當前日期
        if (days < 0) {
            throw new DateTimeException("開始時間不能晚於結束時間!")
        } else {
            // 找到第一個星期幾,也就是把第一個星期幾作為工作日期頭指標
            7.times {
                if (currentDate.getDayOfWeek().toString() == englishWeek) {
                    return
                }
                currentDate = currentDate.plusDays(1) // 更新當前日期
            }
            // 查詢剩餘所有的星期幾
            (days / 7 + 1).times {
                if (currentDate.getDayOfWeek().toString() == englishWeek) {
                    weeks << currentDate
                }
                currentDate = currentDate.plusWeeks(1) // 更新當前日期
            }
            return weeks
        }
    }