簡體   English   中英

如何從日期獲得零售(4-5-4)日歷周

[英]How to get Retail (4-5-4) Calendar Week of Month from a date

我需要從一個日期 獲得 4-5-4個日歷周 是否有像Java格魯吉亞日歷這樣的實用程序用於4-5-4零售日歷? 如果沒有,我該如何創建一個? 需要什么邏輯? 在閏年的情況下,第53周是什么時候?

例如,如果我將日期(DD-MM-YYY) 04-03-2018作為輸入傳遞,我應該將March Week 1作為輸出。 或者,如果我將01-04-2018作為輸入,我應該將March Week 5作為輸出。

請通過提供構建此實用程序的方法來幫助我。

內置無支持

現代java.time類和遺留日期時間類( Date / Calendar都不直接支持National Retail Federation 4-5-4 Calendar

實施Chronology

我懷疑解決這個問題的最好方法是為java.time框架實現Chronology

Java 8及更高版本捆綁了五個實現( HijrahChronologyIsoChronologyJapaneseChronologyMinguoChronologyThaiBuddhistChronology )。 他們的源代碼可以在OpenJDK項目中找到。

ThreeTen-Extra項目提供了十多個年表AccountingChronologyBritishCutoverChronologyCopticChronologyDiscordianChronologyEthiopicChronologyInternationalFixedChronologyJulianChronologyPaxChronologySymmetry010ChronologySymmetry454Chronology ),其源代碼可能有所幫助。

以下類應該這樣做:

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周。 我把它留給你。 我會有一個非常徹底的單元測試。

請檢查我的理解是否與您的理解一致:如果我從羅伯特布爾克在他的答案中鏈接的示例日歷中正確理解,那么NRF 4-5-4歲從2月開始。 它的周數從星期日開始,一年的第一周是包含2月至少4天的第一周。 換句話說,包含2月4日的那一周。換句話說,從1月29日到2月4日的間隔周日開始的一周。3月,6月,9月和12月的月份總是有5周。 在53周的情況下,1月也有5周。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM