如何从日期

时间:2018-03-19 17:20:33

标签: java calendar

我需要 从日期开始的4-5-4日历周。是否有像Java格鲁吉亚日历这样的实用程序用于4-5-4零售日历? 如果没有,我该如何创建一个?需要什么逻辑?在闰年的情况下,第53周是什么时候?

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

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

2 个答案:

答案 0 :(得分:2)

内置无支持

现代 java.time 类和旧版日期时间类(Date / Calendar)都不直接支持National Retail Federation 4-5-4 Calendar

实施Chronology

我怀疑解决此问题的最佳方法是为 java.time 框架实现Chronology

Java 8及更高版本捆绑了五个实现(HijrahChronologyIsoChronologyJapaneseChronologyMinguoChronologyThaiBuddhistChronology)。它们的源代码可以在 OpenJDK 项目中找到。

ThreeTen-Extra项目提供ten more chronologiesAccountingChronologyBritishCutoverChronologyCopticChronologyDiscordianChronologyEthiopicChronology,{{1 }},InternationalFixedChronologyJulianChronologyPaxChronologySymmetry010Chronology),其源代码可能有所帮助。

答案 1 :(得分:2)

以下课程应该这样做:

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.time,现代Java日期和时间API,它并不算太糟糕。

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

请检查我的理解是否与您的理解一致:如果我从example calendars罗勒布尔克与in his answer相关的正确理解,那么NRF 4-5-4岁从2月开始。它的周数从星期日开始,一年的第一周是包含2月至少4天的第一周。换句话说,包含2月4日的那一周。换句话说,从1月29日到2月4日的间隔周日开始的一周。3月,6月,9月和12月的月份总是有5周。如果是53周,那么1月也有5周。