2011-07-19 32 views
7

Tôi nhận được một số kết quả khó hiểu với SimpleDateFormat và tôi hy vọng rằng ai đó có thể làm sáng tỏ một số vấn đề. Đầu ra:SimpleDateFormat Tính toán tuần

Time   = Mon Dec 27 00:00:00 PST 2010 
2010-01 <--- THIS IS WHAT I DON'T UNDERSTAND 
Start of week = Sun Dec 26 00:00:00 PST 2010 
2010-01 
End of Week = Sat Jan 01 23:59:59 PST 2011 
2011-01 

Tôi có nên xử lý "tuần" cuối cùng của năm kéo dài sang năm tiếp theo như trường hợp đặc biệt không? Hay đây là cách chính xác để giải thích điều này? Rõ ràng là khi cố gắng tổ chức tuần tuần tự, thứ tự không chính xác. Điều chỉnh giá trị ban đầu, ngày 25 tháng 12 năm 2005 được coi là tuần thứ 53. Tôi chưa xem Joda để xem liệu Joda có tạo ra kết quả tương tự hay không.

Mã liên quan:

private static Date getStartOfWeek(Date d) { 
    Calendar calendar = Calendar.getInstance(); 
    calendar.clear(); 
    calendar.setTime(d); 

    calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek()); 

    return calendar.getTime(); 
} 

private static Date getEndOfWeek(Date d) { 
    Calendar calendar = Calendar.getInstance(); 
    calendar.clear(); 

    calendar.setTime(d); 
    calendar.add(Calendar.WEEK_OF_YEAR, 1); 
    calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek()); 
    calendar.add(Calendar.MILLISECOND, -1); 

    return calendar.getTime(); 
} 


Calendar calendar = Calendar.getInstance(); 
calendar.clear(); 
calendar.set(2010, Calendar.DECEMBER, 27); 
Date d = calendar.getTime(); 
Date start = getStartOfWeek(d); 
Date end = getEndOfWeek(d); 
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-ww"); 

System.out.println("Time   = " + d); 
System.out.println(fmt.format(d)); 
System.out.println("Start of week = " + start); 
System.out.println(fmt.format(start)); 
System.out.println("End of Week = " + end); 
System.out.println(fmt.format(end)); 

Bối cảnh: Tôi thấy điều này khi sử dụng crosstab (ngày chia thành các nhóm tuần) trong JasperReports.

EDIT: Tôi đang sử dụng JDK 1.6.0_25

EDIT: Có vẻ như rằng tôi sẽ phải sử dụng Joda để có được kết quả chính xác. Để bắt đầu/kết thúc tuần, tôi đã sử dụng: LocalDate.withDayOfWeek. Để truy xuất số năm và số tuần, tôi đã sử dụng DateTime.getWeekyearDateTime.getWeekOfWeekyear.

+0

+1 để đưa ra một vấn đề tinh tế trong biểu diễn ngày tháng. Xem câu trả lời của tôi dưới đây. –

Trả lời

14

Lỗi này nằm trong mã định dạng của bạn, chứ không phải Java.

Hành vi đáng ngạc nhiên là do quy tắc bí truyền trong ký hiệu ngày tháng. Lưu ý rằng ISO 8601 (khá gây nhầm lẫn) chỉ định các quy tắc khác nhau cho ranh giới năm khi sử dụng số tuần. Đặc biệt, 2010-12-27 được coi là một phần của năm 2011 khi sử dụng số tuần.

Do đó, bạn nên sử dụng "năm tuần" YYYY thay vì năm thông thường yyyy. (Xem http://download.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html#week_year và ví dụ cuối cùng trong http://download.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html.)

Ngoài ra, ký pháp chuẩn cho ngày sử dụng rõ ràng 'W', vì vậy bạn nên sử dụng new SimpleDateFormat("YYYY-'W'ww") để thay thế.

Chỉnh sửa: Có một vấn đề khác. Java dường như mặc định là phi tiêu chuẩn calendar.getMinimalDaysInFirstWeek() == 1, vì vậy bạn phải đặt

calendar.setMinimalDaysInFirstWeek(4); 

để có được năm chính xác.

Chỉnh sửa: Từ đọc Calendar javadocs, bạn có thể cũng cần đặt ngày bắt đầu thành thứ Hai.Hơn nữa, định dạng số YYYY có vẻ mới trong Java 1.7. Trong điều kiện này, trừ khi bạn sẵn sàng nâng cấp lên phiên bản Java trước khi phát hành, tôi khuyên bạn chỉ nên sử dụng Joda Time.

+0

Cũng không thể nâng cấp lên Java 1.7 vì vậy tôi sẽ phải sử dụng Joda trong thời gian này. – nevets1219

1

java standadr Date & Các lớp thời gian không được thiết kế tốt và đôi khi không hoạt động như mong đợi. sử dụng thay thế Joda Time

+0

Mặc dù tuyên bố của bạn là chính xác, trong trường hợp này không nên có bất kỳ sự khác biệt nào. Vấn đề là làm thế nào "số tuần" được tính – Nivas

-2

Có, đây có vẻ là lỗi trong Java và không phải trong mã định dạng. Nếu bạn in:

System.out.println("Week = " + calendar.get(Calendar.WEEK_OF_YEAR)); 

Nó cũng hiển thị 1.

Nếu bạn thay đổi ngày của bạn để một cái gì đó không quá gần đến cuối năm, ví dụ:

calendar.set(2010, Calendar.NOVEMBER, 27); 

Sau đó, đầu ra có vẻ đúng. BTW, tôi đã thử nghiệm bằng máy ảo Sun 64.0_25 64 bit.

1

Từ ISO Week

Tuần lễ đầu tiên của một năm là tuần có chứa các Thứ Năm đầu tiên năm.

Vì vậy, hành vi không liên quan gì đến Java hoặc Joda. Đây là cách "tuần trong năm" được triển khai trên toàn thế giới (nếu họ tuân theo tiêu chuẩn ISO)