java - 如何从某个日期获取零售 (4-5-4) 月历周数

标签 java calendar

我需要获取某个日期的4-5-4 Calendar Week。 Java 中是否有用于 4-5-4 零售日历的格鲁吉亚日历之类的实用程序? 如果没有,我该如何创建一个?需要什么逻辑?如果是闰年,第 53 周是什么?

例如,如果我将日期 (DD-MM-YYY) 04-03-2018 作为输入,我应该将 March Week 1 作为输出。 或者,如果我将 01-04-2018 作为输入,我应该将 March Week 5 作为输出。

请提供构建此实用程序的方法来帮助我。

最佳答案

下面的类应该这样做:

public class NrfMonthWeek {

    public static NrfMonthWeek getWeek(LocalDate date) {
        // Determine NRF calendar year.
        // The year begins on the Sunday in the interval Jan 29 through Feb 4.
        LocalDate firstDayOfNrfYear = date.with(MonthDay.of(Month.JANUARY, 29))
                .with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        if (date.isBefore(firstDayOfNrfYear)) { // previous NRF year
            firstDayOfNrfYear = date.minusYears(1)
                    .with(MonthDay.of(Month.JANUARY, 29))
                    .with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        }
        // 1-based week of NRF year
        int weekOfNrfYear = (int) ChronoUnit.WEEKS.between(firstDayOfNrfYear, date) + 1;
        assert 1 <= weekOfNrfYear && weekOfNrfYear <= 53 : weekOfNrfYear;
        YearMonth firstMonthOfNrfYear = YearMonth.from(firstDayOfNrfYear)
                .with(Month.FEBRUARY);
        if (weekOfNrfYear == 53) {
            // Special case: the last week of a 53 weeks year belongs to
            // the last month, January; this makes it a 5 weeks month.
            return new NrfMonthWeek(firstMonthOfNrfYear.plusMonths(11), 5);
        } else {
            // 1-based month of NRF year (1 = February through 12 = January).
            // A little math trickery to make the 4-5-4 pattern real.
            int monthOfNrfYear = (weekOfNrfYear * 3 + 11) / 13;
            // Number of weeks before the NRF month: 0 for February, 4 for March, 9 for April, etc.
            int weeksBeforeMonth = (monthOfNrfYear * 13 - 12) / 3;
            int weekOfMonth = weekOfNrfYear - weeksBeforeMonth;
            return new NrfMonthWeek(
                    firstMonthOfNrfYear.plusMonths(monthOfNrfYear - 1), weekOfMonth);
        }
    }

    private YearMonth month;
    /** 1 through 5 */
    private int weekOfMonth;

    public NrfMonthWeek(YearMonth month, int weekOfMonth) {
        this.month = Objects.requireNonNull(month);
        if (weekOfMonth < 1 || weekOfMonth > 5) {
            throw new IllegalArgumentException("Incorrect week number " + weekOfMonth);
        }
        this.weekOfMonth = weekOfMonth;
    }

    @Override
    public String toString() {
        return month.getMonth().getDisplayName(TextStyle.FULL, Locale.US)
                + " Week " + weekOfMonth;
    }
}

让我们试试吧。在这里,我将您问题中的两个日期传递给 getWeek 方法:

    System.out.println(NrfMonthWeek.getWeek(LocalDate.of(2018, Month.MARCH, 4)));
    System.out.println(NrfMonthWeek.getWeek(LocalDate.of(2018, Month.APRIL, 1)));

这会打印所需的内容:

March Week 1
March Week 5

虽然只打印月份和星期,但年份也包含在 getWeek 返回的对象中。

计算月和周的公式是神秘的。我没有很好的论据说明它们为什么起作用,尽管这样的论据可能是可以构建的。我已经用所有相关值对它们进行了测试,你也可以自由地做同样的事情。除此之外,使用现代 Java 日期和时间 API java.time,还不错。

如果是我,我会在 NrfMonthWeek 构造函数中进行更精细的验证,只允许可能有 5 周的月份中的第 5 周。我把它留给你。我会进行非常彻底的单元测试。

请检查我的理解是否与你的一致:如果我从example calendars中理解正确Basil Bourque 链接到 in his answer , NRF 4-5-4 年从二月开始。它的星期从星期日开始,一年中的第一周是包含至少 4 天二月的第一周。换句话说,包含 2 月 4 日的那一周。换句话说,从 1 月 29 日到 2 月 4 日之间的星期日开始的那一周。3 月、6 月、9 月和 12 月总是有 5 周。如果一年有 53 周,一月也有 5 周。

关于java - 如何从某个日期获取零售 (4-5-4) 月历周数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49368843/

相关文章:

Java SSL 握手失败

excel - 如何使用波斯日期(Shamsi)?

php - 返回多个结果的 MySQL 子查询

c - 在C中打印带有月份和年份的日历

java - 如何根据log4j配置文件中的环境更改记录器级别?

java - 数组相交方法中的空指针(java)

python - Python 中星期日 = 0 的星期常量

ios - 日历:获取日期组件,奇怪的情况

java - Java 中的数字到单词

Java byte[] 到字符串转换输出字节