gpt4 book ai didi

java - 使用 Java 8 计算两个日期之间的天数,同时忽略一周中的某些天数

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:04:51 26 4
gpt4 key购买 nike

下面我有3种方法。第一个很简单。它只是计算总天数。但是,第二个不仅会计算天数,还会忽略传递给该方法的星期几。

我的问题是第三种方法并不总是正确的。它应该匹配第二种方法。我猜它与闰年有关,因为当它不正确时,差异通常是 +=3|4 。

附加信息

我试图以某种方式模拟 Excel 的 weekday(serial_number,[return_type]) 公式。

serial_number = startDate:Date - daysOfWeekToInclude:Array<Integer>

例子

  | A       | B                                                  | C
+---------+----------------------------------------------------+-----------
1 | Start | =DATE(2014,9,7) | 9/7/2014
2 | End | =DATE(2025,6,13) | 6/13/2025
3 | Include | ={1,2,4,6} (Mon, Tue, Thu, & Sat) | <Disp Only>
4 | Days | =SUM(INT((WEEKDAY($B$1-{1,2,4,6},1)+$B$2-$B$1)/7)) | 2248

这里有关于此功能的更多信息:How to count / calculate the number of days between two dates in Excel?

原始图像

enter image description here

方法

  1. 简单地计算两个日期之间的天数。

    public static int simpleDaysBetween(final LocalDate start,
    final LocalDate end) {
    return (int) ChronoUnit.DAYS.between(start, end);
    }
  2. 计算天数,忽略一周中的某些天,使用循环。

    public static int betterDaysBetween(final LocalDate start,
    final LocalDate end, final List<DayOfWeek> ignore) {
    int count = 0;
    LocalDate curr = start.plusDays(0);

    while (curr.isBefore(end)) {
    if (!ignore.contains(curr.getDayOfWeek())) {
    count++;
    }
    curr = curr.plusDays(1); // Increment by a day.
    }

    return count;
    }
  3. 计算天数。再次但没有循环。

    public static int bestDaysBetween(final LocalDate start,
    final LocalDate end, final List<DayOfWeek> ignore) {
    int days = simpleDaysBetween(start, end);

    if (days == 0) {
    return 0;
    }

    if (!ignore.isEmpty()) {
    int weeks = days / 7;
    int startDay = start.getDayOfWeek().getValue();
    int endDay = end.getDayOfWeek().getValue();
    int diff = weeks * ignore.size();

    for (DayOfWeek day : ignore) {
    int currDay = day.getValue();
    if (startDay <= currDay) {
    diff++;
    }
    if (endDay > currDay) {
    diff++;
    }
    }

    if (endDay > startDay) {
    diff -= endDay - startDay;
    }

    return days - diff;
    }

    return days;
    }

完整代码

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;

public class DayCounter {
public static void main(String[] args) {
final LocalDate start = LocalDate.of(2014, 9, 7);
final LocalDate end = LocalDate.of(2025, 6, 13);
List<DayOfWeek> ignore = Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY);

print(start);
print(end);

System.out.println(simpleDaysBetween(start, end));
System.out.println(betterDaysBetween(start, end, ignore));
System.out.println(bestDaysBetween(start, end, ignore));
}

public static void print(LocalDate date) {
System.out.printf("%s -> %s%n", date, date.getDayOfWeek());
}

public static int simpleDaysBetween(final LocalDate start,
final LocalDate end) {
return (int) ChronoUnit.DAYS.between(start, end);
}

public static int betterDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int count = 0;
LocalDate curr = start.plusDays(0);

while (curr.isBefore(end)) {
if (!ignore.contains(curr.getDayOfWeek())) {
count++;
}
curr = curr.plusDays(1); // Increment by a day.
}

return count;
}

public static int bestDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int days = simpleDaysBetween(start, end);

if (days == 0) {
return 0;
}

if (!ignore.isEmpty()) {
int weeks = days / 7;
int startDay = start.getDayOfWeek().getValue();
int endDay = end.getDayOfWeek().getValue();
int diff = weeks * ignore.size();

for (DayOfWeek day : ignore) {
int currDay = day.getValue();
if (startDay <= currDay) {
diff++;
}
if (endDay > currDay) {
diff++;
}
}

if (endDay > startDay) {
diff -= endDay - startDay;
}

return days - diff;
}

return days;
}
}

最佳答案

如果我们谈论 Java 8 API,为什么不相应地使用 Java 8 功能......

static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
return Stream.iterate(start, d->d.plusDays(1))
.limit(start.until(end, ChronoUnit.DAYS))
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}

从 Java 9 开始,我们可以使用更简单的方法

static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
return start.datesUntil(end)
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}

不过,可能值得使用 Set使用优于线性查找而不是 List :

static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
if(ignore.isEmpty()) return start.until(end, ChronoUnit.DAYS);
EnumSet<DayOfWeek> set = EnumSet.copyOf(ignore);
return start.datesUntil(end)
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}

您可以考虑将参数更改为 Set<DayOfWeek> ,因为它不仅效率更高,而且更适合实际用例。而不是 Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY) , 你可以通过 EnumSet.of(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY) , 但您也可以使用像 EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY) 这样的结构, 表示典型的工作日。

您可以避免整天迭代,但需要特别注意极端情况,因此需要进行彻底的测试。并且只会在非常大的范围内得到返回。为了完整起见,这是优化后的变体:

static long daysBetween(LocalDate start, LocalDate end, Set<DayOfWeek> ignore) {
long d1 = start.toEpochDay(), d2 = end.toEpochDay();
if(d1 > d2) throw new IllegalArgumentException();
if(ignore.isEmpty()) return d2 - d1;
int incompleteWeek = 0;
DayOfWeek startDoW = start.getDayOfWeek(), endDoW = end.getDayOfWeek();
if(startDoW != endDoW) {
for(int v1 = startDoW.getValue(), v2 = endDoW.getValue();
v1 != v2 && d1 < d2; v1 = v1%7+1, d1++) {
if(!ignore.contains(DayOfWeek.of(v1))) incompleteWeek++;
}
}
return incompleteWeek + (d2 - d1) * (7 - ignore.size()) / 7;
}

在这里,ignore 的性能set 的查找并不重要,因为我们最多只查找六个值,但是,强制执行 Set ,即没有重复项,允许我们使用集合的大小来计算范围内完整周中包含的天数。完整周的开始日期和(唯一的)结束日期在一周中的同一天。所以代码只需要迭代天数,直到一周的开始和结束日期匹配。

关于java - 使用 Java 8 计算两个日期之间的天数,同时忽略一周中的某些天数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25798876/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com