2014-01-10 46 views
6

有沒有辦法在JodaTime以容易確定哪些星期屬於哪個月?哪幾個星期與哪幾個月有關?

給定月份數的東西會返回與其關聯的年份。如果有4個以上的日子屬於它,那麼一個星期應該與特定的月份相關聯。

In 2014 for month = 1 then weeks = [1, 2, 3, 4, 5] (note 5 weeks because of 4 days rule) 
In 2014 for month = 3 then weeks = [10, 11, 12, 13] (note 4 weeks because of same rule) 

我不想這「手動」計算...

回答

6

你必須實例DateTime對象指定的週數,然後只需讀取其month property(使用Joda-TimeGoogle Guava)。

 DateTime dateTime = new DateTime().withWeekOfWeekyear(i).withDayOfWeek(DateTimeConstants.MONDAY); 
     if (dateTime.dayOfMonth().getMaximumValue() - dateTime.dayOfMonth().get() < 3) { 
      dateTime = dateTime.plusMonths(1); 
     } 
     int month = dateTime.monthOfYear().get(); 

我們還可以使用下面的功能打印所有個月,屬於它們的周:

public static void main(String[] args) { 
    Multimap<Integer, Integer> monthsWithWeeks = LinkedListMultimap.create(); 

    int weeksInYear = new DateTime().withYear(2014).weekOfWeekyear().getMaximumValue(); 
    for (int i = 1; i <= weeksInYear; i++) { 
     DateTime weekDate = new DateTime().withWeekOfWeekyear(i).withDayOfWeek(DateTimeConstants.MONDAY); 
     if (weekDate.dayOfMonth().getMaximumValue() - weekDate.dayOfMonth().get() < 3) { 
      weekDate = weekDate.plusMonths(1); 
     } 
     int month = weekDate.monthOfYear().get(); 
     monthsWithWeeks.put(month, i); 
    } 

    for (Integer month : monthsWithWeeks.keySet()) { 
     System.out.println(String.format("%d => [%s]", month, Joiner.on(',').join(monthsWithWeeks.get(month)))); 
    } 
} 
+0

有趣!我只是害怕今年第一週和最後一週的角落案例:第一週至2014年實際上是2013年1月30日開始的,是否有可能在WeekOfWeekYear = 1時獲得月份= 12的風險?今天運行代碼是有效的,因爲這是一個星期五,但是另一天可能會出錯嗎? – Gevorg

+0

不可以,因爲星期數是固定的 - 無論您是星期五還是星期一運行 - 第1周始終在同一天開始 –

+0

嗯。 'withWeekOfWeekyear'移動一週保留一天,所以'new DateTime().WeekOfWeekyear(1)= 2014-01-03'這是一個星期五,就像今天一樣。 Weeks正式從星期一開始,所以'New DateTime().WeekOfWeekyear(1).withDayOfWeek(DateTimeConstants.MONDAY)'會產生12,這不是想要的行爲。請讓我知道,如果我失去了其他什麼 – Gevorg

0

有趣的問題,雖然我有喬達較小的經驗。我試圖用簡單的計算來解決jata.util類問題,我想它解決了你的問題 - 只有沒有Joda。

方法來積累的所有周數一個月一年:

public static Integer[] getWeeksInMonth(int month, int year) { 
    List<Integer> list = new ArrayList<Integer>(); 
    SimpleDateFormat format = new SimpleDateFormat("w"); 

    Calendar startDate = Calendar.getInstance(); 
    Calendar endDate = Calendar.getInstance(); 

    startDate.set(year, month - 1, 1); 
    startDate.setMinimalDaysInFirstWeek(4); 

    endDate.set(year, month, 0); 

    // Iterate between the start and stop days 
    while (startDate.getTimeInMillis() <= endDate.getTimeInMillis()) { 

     Calendar cal = Calendar.getInstance(); 
     cal.setTime(startDate.getTime()); 
     cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); 
     // System.out.println("Here here " + 
     // cal.get(Calendar.DAY_OF_MONTH)); 

     // Start of the week is Monday - check if dates 1, 2, 3 fall after 
     // Wednesday (specified 4 day rule) 
     if ((startDate.get(Calendar.DAY_OF_WEEK) > Calendar.THURSDAY) 
       && (startDate.get(Calendar.DAY_OF_MONTH) < 4)) { 

      // If they do, move the dates to next immediate start of the 
      // week - making it to 4th 
      startDate.add(Calendar.DAY_OF_MONTH, 
        (4 - startDate.get(Calendar.DAY_OF_MONTH))); 

      // Similarly - check if last dates of the month make less than 4 
      // for that month 
     } else if ((startDate.get(Calendar.DAY_OF_MONTH) > 25) 
       && ((startDate.getActualMaximum(Calendar.DAY_OF_MONTH) - (cal 
         .get(Calendar.DAY_OF_MONTH))) + 1) < 4) { 
      // If they do, move the dates to next immediate start of the 
      // week - making it to next month 

      startDate 
        .add(Calendar.DAY_OF_MONTH, 
          (startDate 
            .getActualMaximum(Calendar.DAY_OF_MONTH) - startDate 
            .get(Calendar.DAY_OF_MONTH)) + 1); 

     } else { 
      // Get the number of the week 
      // System.out.println(startDate.getTime()); 
      int week = Integer.parseInt(format.format(startDate.getTime())); 

      // If December, check if the next year's 1st week falls under 
      // the 4 day rule, if it does then ignore 
      if (!(startDate.get(Calendar.MONTH) == Calendar.DECEMBER && week == 1)) 
       list.add(week); 

      startDate.add(Calendar.WEEK_OF_MONTH, 1); 
     } 
    } 

    return list.toArray(new Integer[list.size()]); 
} 

調用的主要方法:

public static void main(String... args) { 
     int year = 2014; 
     System.out.println(":::: YEAR " + year + " ::::"); 
     for (int j = 1; j <= 12; j++) { 
      Integer[] array = getWeeksInMonth(j, year); 
      System.out.print("For month : " + j); 
      System.out.print(" [ "); 
      for (int i = 0; i < array.length; i++) { 
       System.out.print(array[i] + " "); 
      } 
      System.out.print("]"); 
      System.out.println(); 
     } 
    } 

輸出(可能的測試用例):

:::: YEAR 2014 :::: 
For month : 1 [ 1 2 3 4 5 ] 
For month : 2 [ 6 7 8 9 ] 
For month : 3 [ 10 11 12 13 ] 
For month : 4 [ 14 15 16 17 ] 
For month : 5 [ 18 19 20 21 22 ] 
For month : 6 [ 23 24 25 26 ] 
For month : 7 [ 27 28 29 30 31 ] 
For month : 8 [ 32 33 34 35 ] 
For month : 9 [ 36 37 38 39 ] 
For month : 10 [ 40 41 42 43 44 ] 
For month : 11 [ 45 46 47 48 ] 
For month : 12 [ 49 50 51 52 ] 

您可以驗證其他測試用例,並讓我知道是否有錯誤。我知道很多計算,但它對要求很靈活。

+0

使用JodaTime的時間相同的更短,更簡潔:) –

+0

@JakubK絕對,我+ 1'd爲:),一個有趣的問題,但 – PopoFibo

+0

我會很高興看到Java8版本:) –

0

這是非常簡單的用JodaTime:

/** returns first and last week in a month (must have at least 4 days of that week) 
* Warning: The first week might be week 53 
*/ 
public static int[] firstAndLastWeeksInMonth(int year, int month) { 
    int firstweek = new LocalDate(year, month, 4).getWeekOfWeekyear(); 
    int lastweek = new LocalDate(year, month, 1).plusMonths(1).minusDays(4).getWeekOfWeekyear(); 
    return new int[] { firstweek, lastweek }; 
} 

public static List<Integer> weeksInMonth(int year, int month) { 
    int[] fl = firstAndLastWeeksInMonth(year, month); 
    ArrayList<Integer> weeks = new ArrayList<Integer>(4); 
    weeks.add(fl[0]); 
    for(int w = fl[0] > fl[1] ? 1 : fl[0] + 1; w <= fl[1]; w++) 
     weeks.add(w); 
    return weeks; 
} 

一些輔助代碼,測試:

static void testWeeksInMonth(int year, int month, boolean printdetail) { 
     List<Integer> weeks = weeksInMonth(year, month); 
     System.out.printf("weeks for %d/%d: [%s]\n", year, month, weeks); 
     LinkedHashMap<Integer, Integer> whist = new LinkedHashMap<Integer, Integer>(); 
     LocalDate d1 = new LocalDate(year, month, 1); 
     LocalDate d2 = d1.plusMonths(1); 
     for(LocalDate d = d1; d.isBefore(d2); d = d.plusDays(1)) { 
      int wd = d.getWeekOfWeekyear(); 
      if(!whist.containsKey(wd)) whist.put(wd, 0); 
      whist.put(wd, whist.get(wd) + 1); 
     } 
     List<Integer> weeks2 = new ArrayList<Integer>(); 
     for(Integer wd : whist.keySet()) { 
      if(printdetail) System.out.printf(" (%d: %d) ", wd, whist.get(wd)); 
      if(whist.get(wd) >= 4) weeks2.add(wd); 
     } 
     if(printdetail) System.out.println(""); 
     if(!weeks.equals(weeks2)) { throw new RuntimeException("bad values"); } 

    } 

    public static void main(String[] args) { 
     LocalDate d = new LocalDate(2010, 1, 1); 
     for(int i = 0; i < 60; i++) { 
      testWeeksInMonth(d.getYear(), d.getMonthOfYear(), true); 
      d = d.plusMonths(1); 
     } 
    }