Joda Time minusweeks() 和 plusweeks() 超过一年打破 2014/2015 细分?

Joda Time minusweeks() and plusweeks() over year break 2014/2015 breakdown?

我可能在这里遗漏了一些东西,但我似乎无法在 Joda Time 的文档中或任何地方找到解释。从一年到下一年,在计算周时加减周时,Joda Time 似乎崩溃了。

谁能解释为什么会发生这种情况以及如何正确地做到这一点?

我从下面的代码中得到以下输出:

2015-01-08 - This is the current week
2015-01-01 - Removed one week
2014-12-25 - Removed one week
2014-12-17 - Removed one week //for some reason, program backed 8 days here
2014-12-10 - Removed one week
2014-12-17 - Added one week
2014-12-24 - Added one week
2014-12-31 - Added one week
2014-01-08 - Added one week //for some reason, program forwarded 8 days here, but it did not forward to 2015.

原码

import org.joda.time.*;

public class WonkyWeeks {
    int year;
    int week;

    public void backUpOneWeek() {
        LocalDate today = new LocalDate()
                .withDayOfWeek(4)
                .withWeekOfWeekyear(week)
                .withYear(year);
        LocalDate lastWeek = today.minusWeeks(1);

        week = lastWeek.getWeekOfWeekyear();
        year = lastWeek.getYear();
        System.out.println(lastWeek+" - Removed one week");
    }

    public void forwardOneWeek() {
        LocalDate today = new LocalDate()
                .withDayOfWeek(4)
                .withWeekOfWeekyear(week)
                .withYear(year);
        LocalDate nextWeek = today.plusWeeks(1);

        week = nextWeek.getWeekOfWeekyear();
        year = nextWeek.getYear();
        System.out.println(nextWeek+" - Added one week");
    }

    public void thisWeek() {
        LocalDate thisWeek = new LocalDate()
                .withDayOfWeek(4)
                .withWeekOfWeekyear(week)
                .withYear(year);
        System.out.println(thisWeek+" - This is the current week");
    }

    public static void main(String[] args) {
        WonkyWeeks wonky = new WonkyWeeks();
        wonky.week = 2;
        wonky.year = 2015;
        wonky.thisWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
    }
}

进一步测试后,它变得更加混乱。我尝试只添加和删除天而不是周,但出于某种原因,它似乎跳过了日期。

输出:

2015-01-08 - This is the current week
2015-01-07 - removed one day
2015-01-06 - removed one day
2015-01-05 - removed one day
2015-01-04 - removed one day
2015-01-03 - removed one day
2015-01-02 - removed one day
2015-01-01 - Removed one full week
2014-12-31 - removed one day
2014-12-30 - removed one day
2014-12-29 - removed one day
2014-12-28 - removed one day
2014-12-27 - removed one day
2014-12-26 - removed one day
2014-12-25 - Removed one full week
2014-12-23 - removed one day // For some reason, it skipped 2014-12-24?
2014-12-22 - removed one day
2014-12-21 - removed one day
2014-12-20 - removed one day
2014-12-19 - removed one day
2014-12-18 - removed one day
2014-12-17 - Removed one full week
2014-12-16 - removed one day
2014-12-15 - removed one day
2014-12-14 - removed one day
2014-12-13 - removed one day
2014-12-12 - removed one day
2014-12-11 - removed one day
2014-12-10 - Removed one full week
2014-12-11 - added one day
2014-12-12 - added one day
2014-12-13 - added one day
2014-12-14 - added one day
2014-12-15 - added one day
2014-12-16 - added one day
2014-12-17 - Added one week
2014-12-18 - added one day
2014-12-19 - added one day
2014-12-20 - added one day
2014-12-21 - added one day
2014-12-22 - added one day
2014-12-23 - added one day
2014-12-24 - Added one week
2014-12-25 - added one day
2014-12-26 - added one day
2014-12-27 - added one day
2014-12-28 - added one day
2014-12-29 - added one day
2014-12-30 - added one day
2014-12-31 - Added one week
2014-01-02 - added one day //Skipped 2014-01-01 and did not forward to 2015
2014-01-03 - added one day
2014-01-04 - added one day
2014-01-05 - added one day
2014-01-06 - added one day
2014-01-07 - added one day
2014-01-08 - Added one week

进一步测试代码

import org.joda.time.*;

public class WonkyWeeks {
    int year;
    int week;

    public void backUpOneWeek() {
        LocalDate today = new LocalDate()
                .withDayOfWeek(4)
                .withWeekOfWeekyear(week)
                .withYear(year);
        LocalDate adayago = today.minusDays(1);
        System.out.println(adayago+" - removed one day");
        LocalDate twodaysago = adayago.minusDays(1);
        System.out.println(twodaysago+" - removed one day");
        LocalDate threedaysago = twodaysago.minusDays(1);
        System.out.println(threedaysago+" - removed one day");
        LocalDate fourdaysago = threedaysago.minusDays(1);
        System.out.println(fourdaysago+" - removed one day");
        LocalDate fivedaysago = fourdaysago.minusDays(1);
        System.out.println(fivedaysago+" - removed one day");
        LocalDate sixdaysago = fivedaysago.minusDays(1);
        System.out.println(sixdaysago+" - removed one day");
        LocalDate lastWeek = sixdaysago.minusDays(1);

        week = lastWeek.getWeekOfWeekyear();
        year = lastWeek.getYear();
        System.out.println(lastWeek+" - Removed one full week");
    }
    public void forwardOneWeek() {
        LocalDate today = new LocalDate()
                .withDayOfWeek(4)
                .withWeekOfWeekyear(week)
                .withYear(year);
        LocalDate tomorrow = today.plusDays(1);
        System.out.println(tomorrow+" - added one day");
        LocalDate dayAfterTomorrow = tomorrow.plusDays(1);
        System.out.println(dayAfterTomorrow+" - added one day");
        LocalDate threeDaysFromNow = dayAfterTomorrow.plusDays(1);
        System.out.println(threeDaysFromNow+" - added one day");
        LocalDate fourDaysFromNow = threeDaysFromNow.plusDays(1);
        System.out.println(fourDaysFromNow+" - added one day");
        LocalDate fiveDaysFromNow = fourDaysFromNow.plusDays(1);
        System.out.println(fiveDaysFromNow+" - added one day");
        LocalDate sixDaysFromNow = fiveDaysFromNow.plusDays(1);
        System.out.println(sixDaysFromNow+" - added one day");
        LocalDate nextWeek = sixDaysFromNow.plusDays(1);

        week = nextWeek.getWeekOfWeekyear();
        year = nextWeek.getYear();
        System.out.println(nextWeek+" - Added one week");
    }
    public void thisWeek() {
        LocalDate thisWeek = new LocalDate()
                .withDayOfWeek(4)
                .withWeekOfWeekyear(week)
                .withYear(year);
        System.out.println(thisWeek+" - This is the current week");
    }
    public static void main(String[] args) {
        WonkyWeeks wonky = new WonkyWeeks();
        wonky.week = 2;
        wonky.year = 2015;
        wonky.thisWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
    }
}

我看不出你的逻辑有任何问题。在尝试了不同的场景并调试了一些代码之后,我相信这是由于 dayOfWeek 不同年份的行为所致。

这可能无法为您的问题提供完整的答案,但可能会给您一些提示。

无论年份如何,您总是超过 4th 星期几。但它代表不同的日子取决于年份。 例如,如果您传递 day as 4, week 1 and year 2013 然后调用 getDayOfWeek(),您将获得值 2(星期二)。

同样,2014 年 getDayOfWeek() 将 return 3(星期三),2015 年将是 4(星期四)。

所以对于 2015 年,第 4 天代表 Thursday,而对于 2014 年它代表 Wednesday

现在让我们看看您的用例:

  • 2015-01-08 - 这是本周(第 2 周,第 4 天 - 星期四)。
  • 2015-01-01 - 删除一周 -(第 1 周,第 4 天 - 星期四)。
  • 2014-12-25 - 删除一周 -(第 4 周,第 4 天 - 星期四)。
  • 2014-12-17 - 删除一周 -(此处更正 - 第 3 周,第 1 天 4 日 - 星期三)。

我不确定为什么 2014-12-25 没有更正。

Joda-Time 是正确的,但不是您的逻辑。您必须仔细区分 "calendar year"(从一月一日开始)和星期日期的年份(如 ISO-8601 中所定义,也称为 "week-based-year" 或简称 "week-year").

例如,您在 class 中使用两个彼此不严格相关的成员来存储中间结果:

week = nextWeek.getWeekOfWeekyear();
year = nextWeek.getYear();

这些行的问题在于周与基于周的年份相关,而不是如第二行所示与日历年相关。请记住,基于周的年份可能比一月一日的日历年少一年。例如 [2014-12-31] 与 [2015-W01-3] 的日期相同。另请记住,Joda-Time 提供了另一种称为 getWeekyear().

的方法

然后您将使用这两个值以这种方式操作日期:

LocalDate today = new LocalDate()
        .withDayOfWeek(4)
        .withWeekOfWeekyear(week)
        .withYear(year);

又是同样的术语问题。当试图在当前 week-year 2015 年,而不是 2014 年,产生了意想不到的日期变化!整个代码产生的结果并不是真正可预测的,并且会让每个人都感到惊讶。另一个大问题是 方法调用的顺序 这很重要,因为周操作指的是当前的周年(哪一个?!)。以下代码看起来更健康:

LocalDate today = new LocalDate()
        .withWeekyear(year)
        .withWeekOfWeekyear(week)
        .withDayOfWeek(4);

解决方案: 因此,您最好在代码中引用周年,而不是日历年。甚至更好:如果您只想添加或删除周数,那么我建议您改为存储日期(作为 LocalDate 类型的对象)并应用 date.plusWeeks(1) 或类似日期。您始终可以查询日期的星期几、星期几、星期几、日历年等。比保存星期几和日历年要好得多。

测试后更新:

我现在已经将年份更改为星期年,并且还更改了设置日期时方法调用的顺序(首先是星期年,然后是星期,最后是星期几)。在这些更改之后,根据我自己的测试,您的代码将正常工作(尽管我仍然建议您简化 class 状态和逻辑)。这是我完整更改和更正的代码:

import org.joda.time.LocalDate;

public class WonkyWeeks {
    int year;
    int week;

    public void backUpOneWeek() {
        LocalDate today =
            new LocalDate().withWeekyear(year).withWeekOfWeekyear(week).withDayOfWeek(4);
        LocalDate adayago = today.minusDays(1);
        System.out.println(adayago + " - removed one day");
        LocalDate twodaysago = adayago.minusDays(1);
        System.out.println(twodaysago + " - removed one day");
        LocalDate threedaysago = twodaysago.minusDays(1);
        System.out.println(threedaysago + " - removed one day");
        LocalDate fourdaysago = threedaysago.minusDays(1);
        System.out.println(fourdaysago + " - removed one day");
        LocalDate fivedaysago = fourdaysago.minusDays(1);
        System.out.println(fivedaysago + " - removed one day");
        LocalDate sixdaysago = fivedaysago.minusDays(1);
        System.out.println(sixdaysago + " - removed one day");
        LocalDate lastWeek = sixdaysago.minusDays(1);

        week = lastWeek.getWeekOfWeekyear();
        year = lastWeek.getWeekyear();
        System.out.println(lastWeek + " - Removed one full week");
    }

    public void forwardOneWeek() {
        LocalDate today =
            new LocalDate().withWeekyear(year).withWeekOfWeekyear(week).withDayOfWeek(4);
        LocalDate tomorrow = today.plusDays(1);
        System.out.println(tomorrow + " - added one day");
        LocalDate dayAfterTomorrow = tomorrow.plusDays(1);
        System.out.println(dayAfterTomorrow + " - added one day");
        LocalDate threeDaysFromNow = dayAfterTomorrow.plusDays(1);
        System.out.println(threeDaysFromNow + " - added one day");
        LocalDate fourDaysFromNow = threeDaysFromNow.plusDays(1);
        System.out.println(fourDaysFromNow + " - added one day");
        LocalDate fiveDaysFromNow = fourDaysFromNow.plusDays(1);
        System.out.println(fiveDaysFromNow + " - added one day");
        LocalDate sixDaysFromNow = fiveDaysFromNow.plusDays(1);
        System.out.println(sixDaysFromNow + " - added one day");
        LocalDate nextWeek = sixDaysFromNow.plusDays(1);

        week = nextWeek.getWeekOfWeekyear();
        year = nextWeek.getWeekyear();
        System.out.println(nextWeek + " - Added one week");
    }

    public void thisWeek() {
        LocalDate thisWeek =
            new LocalDate().withWeekyear(year).withWeekOfWeekyear(week).withDayOfWeek(4);
        System.out.println(thisWeek + " - This is the current week");
    }

    public static void main(String[] args) {
        WonkyWeeks wonky = new WonkyWeeks();
        wonky.week = 2;
        wonky.year = 2015;
        wonky.thisWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.backUpOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
        wonky.forwardOneWeek();
    }
}

更改代码的输出:

2015-01-08 - This is the current week
2015-01-07 - removed one day
2015-01-06 - removed one day
2015-01-05 - removed one day
2015-01-04 - removed one day
2015-01-03 - removed one day
2015-01-02 - removed one day
2015-01-01 - Removed one full week
2014-12-31 - removed one day
2014-12-30 - removed one day
2014-12-29 - removed one day
2014-12-28 - removed one day
2014-12-27 - removed one day
2014-12-26 - removed one day
2014-12-25 - Removed one full week
2014-12-24 - removed one day
2014-12-23 - removed one day
2014-12-22 - removed one day
2014-12-21 - removed one day
2014-12-20 - removed one day
2014-12-19 - removed one day
2014-12-18 - Removed one full week
2014-12-17 - removed one day
2014-12-16 - removed one day
2014-12-15 - removed one day
2014-12-14 - removed one day
2014-12-13 - removed one day
2014-12-12 - removed one day
2014-12-11 - Removed one full week
2014-12-12 - added one day
2014-12-13 - added one day
2014-12-14 - added one day
2014-12-15 - added one day
2014-12-16 - added one day
2014-12-17 - added one day
2014-12-18 - Added one week
2014-12-19 - added one day
2014-12-20 - added one day
2014-12-21 - added one day
2014-12-22 - added one day
2014-12-23 - added one day
2014-12-24 - added one day
2014-12-25 - Added one week
2014-12-26 - added one day
2014-12-27 - added one day
2014-12-28 - added one day
2014-12-29 - added one day
2014-12-30 - added one day
2014-12-31 - added one day
2015-01-01 - Added one week
2015-01-02 - added one day
2015-01-03 - added one day
2015-01-04 - added one day
2015-01-05 - added one day
2015-01-06 - added one day
2015-01-07 - added one day
2015-01-08 - Added one week