3

我需要获得周跨度:周开始(Mo)| 一年中的星期几结束(星期日)。

例如,对于 5.9.2019,它应该是 241-247(从 0 开始的天数)。

但是,我的方法产生 250 | 249

public static Pair<Integer, Integer> getWeekSpan(Timestamp date) {
        Pair<Integer, Integer> result = new Pair<Integer, Integer>();
        Calendar cal = timestampToCalendar(date);

        // start of week
        cal.set(Calendar.DAY_OF_WEEK, cal.getActualMinimum(Calendar.DAY_OF_WEEK));
        result.setKey(cal.get(Calendar.DAY_OF_YEAR) - 1);

        // end of week
        cal.set(Calendar.DAY_OF_WEEK, cal.getActualMaximum(Calendar.DAY_OF_WEEK));
        result.setValue(cal.get(Calendar.DAY_OF_YEAR) - 1);

        return result;
    }
    public static Calendar timestampToCalendar(Timestamp timestamp) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(timestamp.getTime());
        return cal;
    }
4

3 回答 3

4

java.time

public static Pair<Integer, Integer> getWeekSpan(LocalDate date) {
    return new Pair<>(getZeroBasedDayOfYear(date.with(DayOfWeek.MONDAY)),
            getZeroBasedDayOfYear(date.with(DayOfWeek.SUNDAY)));
}

private static int getZeroBasedDayOfYear(LocalDate date) {
    return date.getDayOfYear() - 1;
}

输出:

[244, 250]

它与您所说的预期不完全一致,但它确实与我在您自己的答案中运行代码所得到的一致,所以我相信它是正确的。这些数字对应于 2019 年 9 月 2 日星期一和 2019 年 9 月 8 日星期日。

我不知道你的Pair类是否有一个 2 参数构造函数。如果不是,我相信您会像在问题中那样填写这两个整数。

请注意,一周可能会跨过新年。例如,如果我指定 2019-12-31,我会得到:

[363, 4]

4 指次年的 1 月 5 日。

我的代码依赖于您想要 ISO 周这一事实,其中星期一是一周的第一天。如果需要,我们可以通过WeekFields对象引入更多的灵活性:

public static Pair<Integer, Integer> getWeekSpan(LocalDate date) {
    WeekFields wf = WeekFields.ISO;
    return new Pair<>(getZeroBasedDayOfYear(date.with(wf.dayOfWeek(), 1)),
            getZeroBasedDayOfYear(date.with(wf.dayOfWeek(), 7)));
}

只要我使用WeekFields.ISO,结果仍然相同,但这是您可以插入的地方,例如,WeekFields.of(Locale.getDefault())如果您想使用默认语言环境的星期定义。

您使用的类TimestampCalendar设计不佳且早已过时。我建议你不要使用它们。相反,我使用LocalDate的是现代 Java 日期和时间 API 的 java.time。

如果您Timestamp从旧 API 中获得了一个无法更改或不想升级的对象,则转换为 a 的方法LocalDate是:

    LocalDate convertedLocalDate = yourTimestamp.toInstant()
            .atZone(ZoneId.systemDefault())
            .toLocalDate();

你的代码出了什么问题?

这是Calendar课堂变得混乱的地方之一。它对一周中的天数进行编号,从周日的 1 到周六的 7。因此,当您询问实际的最小值和最大值时,您会得到 1 代表星期日和 7 代表星期六,即使这些不是一周的第一天和最后一天。所以发生的事情是,您首先将星期几设置为星期日,得到 9 月 8 日,因为您的一周从星期一开始。顺便提一句,Calendar.getInstance()从您的默认语言环境中获取星期定义,该定义无法从代码中读取,并且可能也会使许多人感到困惑。如果有一天您的代码在具有不同默认语言环境的 JVM 上运行并且突然表现不同,则更是如此。接下来,将星期几设置为最大值 7 时,您得到了 9 月 7 日星期六。日期被正确转换为 250 和 249。

关联

Oracle 教程:日期时间解释如何使用 java.time。

于 2019-09-05T16:35:43.093 回答
1
于 2019-09-06T18:23:20.343 回答
0

设置严格的周一和周日解决了这个问题。

public static Pair<Integer, Integer> getWeekSpan(Timestamp date) {
        Pair<Integer, Integer> result = new Pair<Integer, Integer>();
        Calendar cal = timestampToCalendar(date);

        // start of week
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        result.setKey(cal.get(Calendar.DAY_OF_YEAR) - 1);

        // end of week
        cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        result.setValue(cal.get(Calendar.DAY_OF_YEAR) - 1);

        return result;
    }

编辑:但是这段代码确实解决了最初的问题,它没有解决时区问题使用不推荐使用的类。有关更多详细信息,请参阅其他答案。

于 2019-09-05T13:11:18.207 回答