Làm thế nào để tìm tổng số tuần trong một năm trong Java?


11

Tôi đang làm việc trên một dự án. Ở đó tôi nên tìm tổng số tuần trong một năm. Tôi đã thử với mã sau đây, nhưng tôi nhận được câu trả lời sai: 2020 có 53 tuần, nhưng mã này cho 52 tuần.

Tôi đã sai ở đâu trong mã này?

package com.hib.mapping;

import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.joda.time.DateTime;

public class TestWeek {

    public static void main(String args[]) {
        System.out.println(getWeeks());
    }

    public static int getWeeks() {

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, 2020);
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        GregorianCalendar gregorianCalendar = new GregorianCalendar();

        int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (gregorianCalendar.isLeapYear(2020)) {
            if (weekDay == Calendar.THURSDAY || weekDay == Calendar.WEDNESDAY)
                return 53;
            else
                return 52;
        } else {
            if (weekDay == Calendar.THURSDAY)
                return 53;
            else
                return 52;
        }

    }

}

Đầu ra:

52


1
Không chính xác là một bản sao, nhưng nên đọc: stackoverflow.com/questions/44197872/ trên
Federico klez Culloca

1
Đề nghị cung cấp định nghĩa của bạn về một tuần.
Andy

4
Đó là năm 2020. Xin vui lòng tránh sử dụng api ngày cũ rắc rối xung quanh DateCalendar. Sử dụng java.timethay thế, nó là tốt hơn và đơn giản hơn nhiều.
Zabuzard

Nếu (năm là năm nhuận) và (ngày 1 tháng 1 là Chủ nhật) thì 54 ngày khác 53.
Akina

bạn có thể cho tôi một số mã?
Kumaresan Perumal

Câu trả lời:


7

Sử dụng định nghĩa Wikipedia ở đây . Một năm có 53 tuần nếu ngày 1 tháng 1 là thứ năm hoặc ngày 31 tháng 12 là thứ năm, nếu không thì có 52 tuần. Định nghĩa này tương đương với định nghĩa bạn đã sử dụng. Tôi nghĩ rằng đây là một cách dễ dàng hơn để kiểm tra, vì bạn không cần phải kiểm tra năm nhuận.

Sử dụng java.timeAPI Java 8 :

int year = 2020;
boolean is53weekYear = LocalDate.of(year, 1, 1).getDayOfWeek() == DayOfWeek.THURSDAY ||
        LocalDate.of(year, 12, 31).getDayOfWeek() == DayOfWeek.THURSDAY;
int weekCount = is53weekYear ? 53 : 52;

Tuần tối đa của năm 53. Tôi nghĩ thật tốt @ Naman không có 54 tuần, tôi nghĩ giải pháp chính xác là LocalDate.of (i, 1, 1) .range (WeekFields.ISO.weekOfWeekBasingYear ()). GetMaximum ()
Kumaresan Perumal

1
nó cho 53 tuần cho năm 2021. Tôi nghĩ đó là sai. vui lòng kiểm tra nó
Kumaresan Perumal

1
@KumaresanPerumal Bạn có chắc không?
Quét

1
Vâng, nó đang hoạt động. Tôi sẽ kiểm tra với 100 năm sau đó cho bạn biết. cảm ơn vì nỗ lực của bạn
Kumaresan Perumal

1
Tôi đã thử nghiệm trên JDK 1.8.0_101 và 1.8.0_121. Vẫn nhận được 52 tuần vào năm 2021 như chúng ta nên làm.
Ole VV

7

tl; dr

Đối với một tuần ISO 8601 tiêu chuẩn, hãy sử dụng YearWeeklớp từ thư viện ThreeTen-Extra với một tuyên bố tạm thời.

YearWeek          // Represents an entire week of a week-based-year.
.of( 2020 , 1 )   // Pass the number of the week-based-year (*not* calendar year), and a week number ranging from 1 to 52 or 1 to 53.
.is53WeekYear()   // Every standard week-based-year has either 52 or 52 complete weeks.
? 53              // Ternary statement returns 53 if the predicate returns True, …
: 52              // … otherwise returns 52. 

Đó là, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52

Xác định hàng tuần

Bạn cần xác định một tuần. Trong mẫu mã của bạn, định nghĩa về tuần thay đổi theo mặc định hiện tại của JVM Locale. Vì vậy, kết quả của bạn có thể thay đổi trong thời gian chạy.

Mã của bạn cũng sử dụng các lớp thời gian ngày khủng khiếp đã được thay thế bởi các lớp java.time hiện đại . Ngừng sử dụng GregorianCalendar& Calendar; họ đã được thay thế vì lý do tốt.

ISO 8601 tuần

Các tiêu chuẩn ISO 8601 tiêu chuẩn định nghĩa một tuần như sau:

  • Tuần bắt đầu vào thứ Hai , kết thúc vào Chủ nhật.
  • Tuần # 1 có thứ Năm đầu tiên của năm dương lịch.

Định nghĩa đó có nghĩa là:

  • Những ngày đầu tiên và cuối cùng của một năm dựa trên tuần có thể là những ngày cuối cùng / hàng đầu của năm trước / năm sau.
  • Năm dựa trên tuần có 52 hoặc 53 tuần hoàn thành.

Nếu định nghĩa của bạn khác, hãy xem Trả lời của Ole VV .

YearWeek:is53WeekYear

Nếu điều này phù hợp với định nghĩa của bạn, thì hãy thêm thư viện ThreeTen-Extra vào dự án của bạn để mở rộng chức năng java.time được tích hợp trong Java 8 trở lên. Sau đó bạn có quyền truy cập vào YearWeeklớp.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearWeek yearWeekNow = YearWeek.now( z ) ;
boolean is53WeekYear = yearWeekNow.is53WeekYear() ;

int weeksLong = yearWeekNow.is53WeekYear() ? 53 : 52 ;

Để hỏi về một năm cụ thể theo tuần, chỉ cần tùy ý chọn bất kỳ tuần nào trong năm. Ví dụ: đối với năm 2020 dựa trên tuần, chúng tôi yêu cầu tuần # 1.

int weeksLong = YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52 ;
LocalDate weekStart = YearWeek.of( 2020 , 1 ).atDay( DayOfWeek.MONDAY ) ;

tuầnLong = 53

tuần Bắt đầu = 2019-12-30

Lưu ý ngày đầu tiên của năm dựa trên tuần 2020 là từ năm dương lịch 2019.


Tôi đang ở Ấn Độ. Tôi có nên chỉ định tên quốc gia?
Kumaresan Perumal

@KumaresanPerumal Không, múi giờ là dành cho now. Vì bạn muốn có được số tuần cho một năm cụ thể, thay vì năm hiện tại, chỉ cần sử dụng YearWeek.of(yourYear, 1).
Quét

ok cảm ơn bạn @sweeper Tôi sẽ sử dụng nó
Kumaresan Perumal

@KumaresanPerumal Wikipedia giữ danh sách tên múi giờ này. Có thể hơi lỗi thời. Theo như tôi biết, tất cả Ấn Độ đều sử dụng múi giờ Asia/Kolkata, hiện tại có độ lệch +05: 30. Trong mã Java : ZoneId.of( "Asia/Kolkata" ). Để biết thêm thông tin và lịch sử, xem Wikipedia, Thời gian ở Ấn Độ .
Basil Bourque

4

Giải pháp linh hoạt

Điều này sẽ làm việc cho bất kỳ sơ đồ đánh số tuần nào có thể được biểu diễn trong một WeekFieldsđối tượng.

public static int noOfWeeks(WeekFields wf, int year) {
    LocalDate lastDayOfYear = YearMonth.of(year, Month.DECEMBER).atEndOfMonth();
    if (lastDayOfYear.get(wf.weekBasedYear()) > year) { // belongs to following week year
        return lastDayOfYear.minusWeeks(1).get(wf.weekOfWeekBasedYear());
    }
    else {
        return lastDayOfYear.get(wf.weekOfWeekBasedYear());
    }
}

Ý tưởng là tìm số tuần của tuần cuối cùng trong năm. Tôi thử đầu tiên với ngày 31 tháng 12, nhưng đó có thể là vào tuần đầu tiên của năm sau. Nếu vậy, tôi đi một tuần trở lại.

Tôi đã thử nghiệm khá kỹ lưỡng với WeekFields.ISO, không quá nhiều với các WeekFieldsđối tượng khác , nhưng như tôi đã nói, tôi tin rằng nó hoạt động.

Nếu bạn biết rằng bạn sẽ luôn cần ISO 8601 tuần, tôi nghĩ bạn nên đi với một trong những câu trả lời hay của SweeperBasil Bourque . Tôi đã đăng bài này trong trường hợp bạn cần một giải pháp linh hoạt hơn để hoạt động với các chương trình đánh số tuần khác.

Sử dụng java.time

Mã trong câu hỏi của bạn thật hài hước ở chỗ nó nhập các lớp cả từ Joda-Time và từ java.time, nhưng vẫn sử dụng bản cũ CalendarGregorianCalendartừ Java 1.1. Các lớp này được thiết kế kém và hiện đã lỗi thời, bạn không nên sử dụng chúng. Joda-Time đang ở chế độ bảo trì, java.time đã tiếp quản sau nó. Đó là những gì tôi sử dụng và khuyên bạn nên sử dụng.


1

Tôi nghĩ rằng điều này cũng nên làm việc tốt:

int year = 2020;
long numOfWeeks = LocalDate.of(year, 1, 1).datesUntil(LocalDate.of(year, 12, 31), Period.ofDays(7)).count();
System.out.println("Weeks: " + numOfWeeks);

Suy nghĩ tốt đẹp. Nó cho kết quả chính xác cho năm 2020 (53 tuần) cũng như năm 2019 và 2021 (mỗi tuần 52 lần). Tuy nhiên, có thể hơi khó để thuyết phục bản thân.
Ole VV

Nó dường như cung cấp 53 tuần cho tất cả các năm nhuận, tuy nhiên, điều đó không chính xác.
Ole VV

@ OleV.V. Hmm, đủ công bằng. Tôi tò mò làm thế nào các tính toán của LocalDate hoạt động dưới mui xe. Trái đất ngu ngốc và đó là chu kỳ thời gian hơi không hoàn hảo, khiến mọi thứ trở nên phức tạp hơn so với thực tế.
Tim Hunter


0

Sau khi thử rất nhiều trong java 8. Tôi không thể tìm ra giải pháp. sau đó tôi đã chuẩn bị ngày và thời gian phụ thuộc vào Joda. Nó đã cho tôi một câu trả lời tốt như tôi mong đợi

mã:

for (int i = 2020; i < 2100; i++) {
  int weeks = new DateTime().withYear(i).weekOfWeekyear().getMaximumValue();
  System.out.println(i + " years : " + weeks); 
}

Phụ thuộc Maven:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.5</version>
</dependency>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.