2011-10-30 71 views
13

Tôi phần nào đấu tranh với điều này.Java: Làm thế nào để tôi có được ngày của x ngày trong một tháng (ví dụ: Thứ hai thứ ba trong tháng 2 năm 2012)

Tôi muốn thiết lập Lịch của mình để giả sử: Thứ hai thứ ba vào tháng 2 năm 2012. Và tôi không tìm thấy cách nào để thực hiện việc này bằng Java.

Ví dụ, nếu tôi muốn thiết lập lịch của tôi cho Giáng sinh năm 2011, tôi có thể làm điều này một cách dễ dàng, theo cách này:

Calendar when = Calendar.getInstance(); 
when.set (Calendar.MONTH, Calendar.DECEMBER); 
when.set (Calendar.DAY_OF_MONTH, 25) 
when.set (Calendar.YEAR, 2011); 

Nhưng tôi đang bị mất như thế nào để thiết lập nó cho chúng ta hãy nói Memorial Day Năm 2012, là Thứ Hai cuối cùng của tháng Năm. Đây là mã của tôi, nhưng nó rõ ràng là sai, bởi vì tôi chỉ đơn giản là không thể giả định rằng ngày Thứ Hai cuối cùng của tháng sẽ được trong tuần 4 tháng 5 năm đó:

Calendar when = Calendar.getInstance(); 
when.set (Calendar.DAY_OF_WEEK,Calendar.MONDAY); 
when.set (Calendar.MONTH, Calendar.MAY); 
when.set (Calendar.WEEK_OF_MONTH, 4) 
when.set (Calendar.YEAR, 2012); 

Bất kỳ lời đề nghị như thế nào tôi programatically có thể tìm thấy ra, trong đó tuần của tháng 5 năm 2012 (ví dụ ở trên) là thứ hai cuối cùng? Giả sử tôi có thể nhận được thông tin đó, tôi sẽ có thể nhận được mã của tôi ở trên để làm việc.

Tôi cần thứ gì đó về cơ bản sẽ hoạt động cho bất kỳ ví dụ nào khác. Một cái gì đó mà có thể cho một ngày chính xác cho các kịch bản tương tự. Ví dụ:

Những ngày là:

  • thứ Năm 03 tháng năm 2015
  • 1st thứ hai của tháng 6 năm 2050
  • 4 thứ ba của tháng 12 năm 2012
  • 2 thứ tư của tháng bảy năm 2000

Tôi thực sự cần điều này cho dự án của tôi và tôi chắc chắn nó đơn giản, nhưng tôi đang phá vỡ đầu của tôi về điều này mà không có bất kỳ kết quả thực sự để hiển thị cho :) Và cũng không thể tìm thấy bất cứ điều gì trên mạng.


Added:

Ok, đây là nơi mà tôi đã có cho ngày Thứ Hai cuối cùng trong một tháng:

when.set (GregorianCalendar.MONTH, GregorianCalendar.MAY); 
when.set (GregorianCalendar.DAY_OF_WEEK, Calendar.MONDAY); 
when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, -1); 
when.set (Calendar.YEAR, 2012); 

Nhưng tôi không chắc chắn làm thế nào tôi sẽ đi về làm ví dụ giây thứ hai trong cùng tháng, như thế này?

when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, 2); 

Mọi đề xuất?

Trả lời

10

để làm ngày số học trong Java (và nói chung, để làm bất cứ điều gì với datetimes, ngoại trừ những điều tầm thường nhất) Joda-Time là câu trả lời:

public static LocalDate getNDayOfMonth(int dayweek,int nthweek,int month,int year) { 
    LocalDate d = new LocalDate(year, month, 1).withDayOfWeek(dayweek); 
    if(d.getMonthOfYear() != month) d = d.plusWeeks(1); 
    return d.plusWeeks(nthweek-1); 
} 

public static LocalDate getLastWeekdayOfMonth(int dayweek,int month,int year) { 
    LocalDate d = new LocalDate(year, month, 1).plusMonths(1).withDayOfWeek(dayweek); 
    if(d.getMonthOfYear() != month) d = d.minusWeeks(1); 
    return d; 
} 

public static void main(String[] args) { 
    // second wednesday of oct-2011 
    LocalDate d = getNDayOfMonth(DateTimeConstants.WEDNESDAY, 2, 10, 2011); 
    System.out.println(d); 
    // last wednesday of oct-2011 
    LocalDate dlast = getLastWeekdayOfMonth(DateTimeConstants.WEDNESDAY, 10, 2011); 
    System.out.println(dlast); 
} 

Sửa: Kể từ Java 8 (2014) Ngày API mới (gói java.time), được lấy cảm hứng từ/tương tự như Jodatime, should be preferred.

+0

Tôi thích mã này rất nhiều, nó thực sự hoạt động. Tôi chỉ không biết làm thế nào để xác định thứ tư cuối cùng (trong trường hợp này) trong tháng. Bạn có thể giúp. – jjj

+0

Tôi đang thử một cái gì đó như: LocalDate d = getNDayOfMonth (DateTimeConstants.WEDNESDAY, -1, 10, 2011); Nhưng nó không hoạt động. – jjj

+0

@jjj: Để có được ngày thứ tư cuối cùng của tháng đòi hỏi một sự thay đổi nhỏ, tôi đã thêm một phương pháp cho điều đó. Bạn cũng có thể sử dụng phương pháp đầu tiên: ví dụ, để có được thứ tư cuối cùng của tháng mười-2001, nhận được thứ tư đầu tiên của nov-2011 và trừ đi một tuần. – leonbloy

4

Tôi không biết cách "dễ dàng" nhưng tôi có thể đề xuất cho bạn những điều sau đây.

  1. Đặt lịch cho ngày đầu tiên của tháng.
  2. Truy lục ngày trong tuần
  3. Tính ngày của Thứ Hai đầu tiên của tháng.
  4. Thêm 14 ngày sử dụng phương thức calendar.add(). Bạn sẽ nhận được thứ hai thứ ba.
0

Bất kỳ cơ hội nào bạn đang sử dụng Quartz scheduler? (?)

public Date date(String cronExpression) { 
    return new org.quartz.CronExpression(cronExpression). 
     getNextValidTimeAfter(new Date(0)); 
} 

System.out.println(date("0 0 0 ? May Thu#3 2015")); 
System.out.println(date("0 0 0 ? Jun Mon#1 2050")); 
System.out.println(date("0 0 0 ? Dec Tue#4 2012")); 
System.out.println(date("0 0 0 ? Jul Wed#2 2000")); 

mã đơn giản này in ra đúng kết quả:

Thu May 21 00:00:00 CEST 2015 
Mon Jun 06 00:00:00 CEST 2050 
Tue Dec 25 00:00:00 CET 2012 
Wed Jul 12 00:00:00 CEST 2000 

Các yêu cầu CronExpression không có bất kỳ phụ thuộc vào phần còn lại của thạch anh, vì vậy bạn có thể cân nhắc sao chép nó vào dự án của bạn (đồng hồ ra cho giấy phép)

Side lưu ý: việc thực hiện nội bộ của getNextValidTimeAfter() là 400 dòng mã ...

1

Tất cả bạn cần là một vòng lặp:

public class CalculateDate { 

public static void main(String ... args) { 

    Calendar c = Calendar.getInstance(); 
    c.set(Calendar.YEAR, 2012); 
    c.set(Calendar.MONTH , Calendar.MAY); 
    c.set(Calendar.DAY_OF_MONTH, 0); 
    c.add(Calendar.DAY_OF_MONTH, -1); 

    System.out.println(c.getTime()); 

    int mondaysCount = 0; 

    while (mondaysCount != 4) { 
     c.add(Calendar.DAY_OF_MONTH, 1); 
     if (c.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
      mondaysCount++; 
     }  
    } 

    System.out.printf("The fourth monday of may is %s", c.getTime());  

} 

} 
-2

Đây là một sự thay thế. Những gì nó làm là: Nhận được tuần bạn muốn (n), và các thông số khác, và trả lại ngày trong ngày trong tuần đó. Vì Lịch cung cấp ngày tháng trước (ví dụ ngày 29 tháng 2 thay vì ngày 7 tháng 3, kể từ tuần đầu tiên của tháng 3 va chạm với tuần cuối cùng của tháng 2), hàm tính tuần thứ 2 nếu ngày vượt quá 7 hoặc bội số của nó cho mỗi tuần của nó. Hy vọng rằng sẽ giúp.

public static int getNthWeekDay (int n, int day, int month, int year) { 
    Calendar calendar = Calendar.getInstance(); 

    calendar.set(Calendar.DAY_OF_WEEK, day); 
    calendar.set(Calendar.MONTH, month); 
    calendar.set(Calendar.WEEK_OF_MONTH,n); 
    calendar.set(Calendar.YEAR, year); 
    if (calendar.get(Calendar.DATE) > n * 7) { 
     calendar.set(Calendar.DAY_OF_WEEK,day); 
     calendar.set(Calendar.MONTH, month); 
     calendar.set(Calendar.WEEK_OF_MONTH,day+1); 

    } 
    return calendar.get(Calendar.DATE); 
} 
+0

Có lẽ tôi không hiểu những gì bạn đang cố gắng làm. Trong năm 2012, tôi đậu (2, 2, 2, 2012) cho phương pháp. Kết quả là tôi nhận được Thứ Hai, 2012-03-05. Tháng là rõ ràng: Java liệt kê bằng 0, vì vậy cho tháng 2 tôi nhận được diễu hành - tốt. Nhưng ngày nào? Tùy thuộc vào miền địa phương, ngày trong tuần được tính vào Chủ nhật (tôi đoán ở Hoa Kỳ) và vào thứ Hai ở nơi khác. Nhưng làm thế nào nó được tính - bằng 1 hoặc 2? Vì vậy, chúng ta có thể có chủ nhật là 0, 1 hoặc 6, 7, và thứ hai là 0, 1 hoặc 2. Vì vậy, thứ hai có một điểm ở đây. Nhưng làm thế nào là thứ hai ngày 5 có thể là thứ hai thứ hai trong tháng ba? Điều đó không đúng. –

5

Các mã sau đây đã được thử nghiệm thành công cho tất cả các ngày lễ trong năm 2013 và 2014. Tôi nhận ra rằng điều này không thực sự trả lời câu hỏi ban đầu, nhưng tôi nghĩ rằng nó có thể có ích cho những người đi qua bài này với hy vọng để tìm ra cách làm việc với các ngày nghỉ bằng Lịch.

public static boolean isMajorHoliday(java.util.Date date) { 
    Calendar cal = Calendar.getInstance(); 
    cal.setTime(date); 

    // check if New Year's Day 
    if (cal.get(Calendar.MONTH) == Calendar.JANUARY 
     && cal.get(Calendar.DAY_OF_MONTH) == 1) { 
     return true; 
    } 

    // check if Christmas 
    if (cal.get(Calendar.MONTH) == Calendar.DECEMBER 
     && cal.get(Calendar.DAY_OF_MONTH) == 25) { 
     return true; 
    } 

    // check if 4th of July 
    if (cal.get(Calendar.MONTH) == Calendar.JULY 
     && cal.get(Calendar.DAY_OF_MONTH) == 4) { 
     return true; 
    } 

    // check Thanksgiving (4th Thursday of November) 
    if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 4 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) { 
     return true; 
    } 

    // check Memorial Day (last Monday of May) 
    if (cal.get(Calendar.MONTH) == Calendar.MAY 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY 
     && cal.get(Calendar.DAY_OF_MONTH) > (31 - 7)) { 
     return true; 
    } 

    // check Labor Day (1st Monday of September) 
    if (cal.get(Calendar.MONTH) == Calendar.SEPTEMBER 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 1 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
     return true; 
    } 

    // check President's Day (3rd Monday of February) 
    if (cal.get(Calendar.MONTH) == Calendar.FEBRUARY 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
     return true; 
    } 

    // check Veterans Day (November 11) 
    if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER 
     && cal.get(Calendar.DAY_OF_MONTH) == 11) { 
     return true; 
    } 

    // check MLK Day (3rd Monday of January) 
    if (cal.get(Calendar.MONTH) == Calendar.JANUARY 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
     return true; 
    } 

    return false; 

} 
0

tl; dr

LocalDate thirdMondayInFebruary2012 = 
    YearMonth.of(2012 , Month.FEBRUARY) 
      .atDay(1) 
      .with(TemporalAdjusters.dayOfWeekInMonth(3 , DayOfWeek.MONDAY)); 

... và ...

LocalDate lastMondayInMay2012 = 
    YearMonth.of(2012 , Month.MAY) 
      .atDay(1); 
      .with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)); 

java.time

Rất dễ dàng để làm bằng cách sử dụng các lớp học java.time mà bây giờ thay thế cả hai Joda- Thời gian và các lớp ngày giờ phiền hà cũ đi kèm với các phiên bản Java sớm nhất.

Trước tiên, chúng tôi cần chỉ định tháng mong muốn. Lớp YearMonth có thể làm điều đó. Từ đó, chúng tôi nhận được LocalDate, một ngày không có thời gian trong ngày và không có múi giờ.

YearMonth ym = YearMonth.of(2012 , Month.FEBRUARY); // Or pass '2' for 'February'. 
LocalDate ld = ym.atDay(1); 

Giao diện TemporalAdjuster cung cấp để điều chỉnh giá trị ngày giờ thành giá trị ngày giờ khác. Triển khai được cung cấp bởi lớp TemporalAdjusters (thông báo số nhiều 's'). Chỉ định một ngày trong tuần bằng cách sử dụng tiện ích DayOfWeek enum.

int ordinal = 3 ; // Use '3' for 'third occurrence in month' such as '3rd Monday'. 
LocalDate thirdMondayInFebruary2012 = ld.with(TemporalAdjusters.dayOfWeekInMonth(ordinal , DayOfWeek.MONDAY)); 

Mẹo: Thay vì vượt qua chỉ số nguyên cho năm và tháng trên cơ sở mã của bạn, vượt qua các đối tượng như YearMonth, Year, Month, và DayOfWeek. Làm như vậy giúp loại bỏ sự mơ hồ, làm cho mã của bạn tự tài liệu hơn, cung cấp types-safety và đảm bảo các giá trị hợp lệ.

Về java.time

Khung java.time được xây dựng vào Java 8 và sau đó. Các lớp này thay thế các lớp ngày giờ phiền hà cũ như java.util.Date, .Calendar, & java.text.SimpleDateFormat.

Dự án Joda-Time, hiện đang ở maintenance mode, khuyên di chuyển sang java.time.

Để tìm hiểu thêm, hãy xem Oracle Tutorial. Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích.

Hầu hết các chức năng java.time được back-chuyển đến Java 6 & 7 trong ThreeTen-Backport và tiếp tục thích nghi với Android trong ThreeTenABP (xem How to use…).

Dự án ThreeTen-Extra mở rộng java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho những bổ sung có thể có trong tương lai vào java.time. Bạn có thể tìm thấy một số lớp học hữu ích tại đây như Interval, YearWeek, YearQuartermore.

0
public String nDow(int year, int month, int nweek, int nday) 
{ 
    Calendar cdt = Calendar.getInstance(); 
    cdt.set(year, month -1, 1); 
    return year + "-" + month + "-" + (getPosOfWeekday(cdt.get(Calendar.DAY_OF_WEEK), nday) + ((nweek - 1) *7)); 
} 

private int getPosOfWeekday(int startday, int nday) 
{ 
    nday = weekDayValue(nday); 
    return constructCircularArray(startday).indexOf(nday) + 1; 
} 

private ArrayList<Integer> constructCircularArray(int weekday) 
{ 
    ArrayList<Integer> circularArray = new ArrayList<Integer>(); 
    for(int i = 0; i < 7; i++) 
    { 
     circularArray.add(i, weekDayValue(weekday++)); 
    } 
    return circularArray; 
} 

private int weekDayValue(int x) 
{ 
    return ((x-1) % 7) + 1; 
} 
+0

nDow (2017, 11, 1, 1) sẽ hiển thị chủ nhật đầu tiên của tháng 11 năm 2017. tuần thứ hai là tuần thứ n trong một tháng và ngày thứ n là tuần thứ n – Kishore

Các vấn đề liên quan