วิธีการหาสัปดาห์รวมของปีใน Java?


11

ฉันกำลังทำงานในโครงการ ที่นั่นฉันควรค้นหาสัปดาห์ทั้งหมดของปี ฉันลองใช้รหัสต่อไปนี้ แต่ฉันได้รับคำตอบที่ผิด: 2020 มี 53 สัปดาห์ แต่รหัสนี้ให้ 52 สัปดาห์

ฉันผิดไปในรหัสนี้ที่ไหน

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;
        }

    }

}

เอาท์พุท:

52


1
ไม่ใช่การอ่านซ้ำที่แนะนำ แต่อย่างใด: stackoverflow.com/questions/44197872/…
Federico klez Culloca

1
แนะนำให้คำจำกัดความของคุณหนึ่งสัปดาห์
Andy

4
มันเป็นปี 2020 หลีกเลี่ยงกรุณาใช้ลำบากเก่าวันมรดก API รอบและDate Calendarใช้java.timeแทนจะดีกว่าและง่ายกว่ามาก
Zabuzard

ถ้า (ปีอธิกสุรทิน) และ (1 ม.ค. เป็นวันอาทิตย์) จากนั้น 54 อื่น 53
Akina

คุณให้รหัสฉันหน่อยได้ไหม
Kumaresan Perumal

คำตอบ:


7

การใช้คำนิยามวิกิพีเดียที่นี่ ปีมี 53 สัปดาห์หาก 1 มกราคมเป็นวันพฤหัสบดีหรือ 31 ธันวาคมเป็นวันพฤหัสบดีมิฉะนั้นจะมี 52 สัปดาห์ คำจำกัดความนี้เทียบเท่ากับที่คุณใช้ ฉันคิดว่านี่เป็นวิธีที่ง่ายกว่าในการตรวจสอบเนื่องจากคุณไม่จำเป็นต้องตรวจสอบปีอธิกสุรทิน

การใช้ Java 8 java.timeAPIs:

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;

สัปดาห์สูงสุดของปี 53 ฉันคิดว่า @Naman ดีไม่มีสัปดาห์ 54 ฉันคิดว่าทางออกที่ถูกต้องคือ LocalDate.of (i, 1, 1) .range (WeekFields.ISO.weekOfWeekBasedYear ()) ()
Kumaresan Perumal

1
มันให้ 53 สัปดาห์สำหรับ 2021 ฉันคิดว่ามันผิด กรุณาทดสอบ
Kumaresan Perumal


1
ใช่มันทำงานอยู่ ฉันจะทดสอบด้วย 100 ปีแล้วบอกคุณ ขอบคุณสำหรับความพยายามของคุณ
Kumaresan Perumal

1
ฉันได้ทดสอบกับ JDK 1.8.0_101 และ 1.8.0_121 ยังคงได้รับ 52 สัปดาห์ในปี 2021 เท่าที่ควร
Ole VV

7

TL; DR

สำหรับมาตรฐาน ISO 8601 สัปดาห์ให้ใช้YearWeekคลาสจากห้องสมุดThreeTen-Extraพร้อมกับคำสั่งที่ประกอบไปด้วยสามส่วน

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. 

นั่นคือ, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52

กำหนด "สัปดาห์"

คุณต้องกำหนดหนึ่งสัปดาห์ Localeในตัวอย่างรหัสของคุณนิยามของสัปดาห์ที่แตกต่างกันไปโดยปริยายปัจจุบัน JVM ของ ดังนั้นผลลัพธ์ของคุณอาจแตกต่างกันในขณะทำงาน

รหัสของคุณยังใช้คลาสวันเวลาที่แย่ซึ่งถูกแทนที่ด้วยคลาสjava.time ที่ทันสมัยเมื่อหลายปีก่อน หยุดใช้GregorianCalendar& Calendar; พวกเขาถูกแทนที่ด้วยเหตุผลที่ดี

ISO 8601 สัปดาห์

8601 ISOมาตรฐานกำหนดสัปดาห์เป็น:

  • สัปดาห์เริ่มต้นในวันจันทร์สิ้นสุดในวันอาทิตย์
  • สัปดาห์ที่ 1 มีวันพฤหัสบดีแรกของปีปฏิทิน

คำจำกัดความนั้นหมายถึง:

  • สองสามวันแรกและสุดท้ายของปีต่อสัปดาห์อาจเป็นวันที่ติดตาม / นำของปีปฏิทินก่อนหน้า / ถัดไป
  • ปีตามสัปดาห์มีทั้ง 52 หรือ 53 สัปดาห์ที่สมบูรณ์

ถ้าความหมายของคุณแตกต่างให้ดูคำตอบโดย Ole VV

YearWeek:is53WeekYear

หากสิ่งนี้ตรงกับคำจำกัดความของคุณให้เพิ่มไลบรารี ThreeTen-Extraเข้ากับโครงการของคุณเพื่อขยายฟังก์ชันการทำงานjava.time ที่สร้างขึ้นใน Java 8 และใหม่กว่า จากนั้นคุณสามารถเข้าถึงYearWeekชั้นเรียน

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

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

หากต้องการถามเกี่ยวกับปีใดสัปดาห์หนึ่งโดยเฉพาะเพียงเลือกสัปดาห์ใด ๆ ของปี ตัวอย่างเช่นสำหรับปี 2020 เราขอสัปดาห์ที่ 1

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

สัปดาห์ยาว = 53

WeekStart = 2019-12-30

ขอให้สังเกตว่าวันแรกของปี 2563 เป็นรายสัปดาห์จากปฏิทินปี 2019 อย่างไร


ฉันอยูู่ในอินเดีย. ฉันควรระบุชื่อประเทศหรือไม่
Kumaresan Perumal

@KumaresanPerumal nowไม่มีเขตเวลาที่มีให้ YearWeek.of(yourYear, 1)ตั้งแต่คุณต้องการที่จะได้รับการนับสัปดาห์สำหรับปีที่เฉพาะเจาะจงแทนของปีปัจจุบันใช้เพียง
กวาด

โอเคขอบคุณ @ ผู้กวาดฉันจะใช้มัน
Kumaresan Perumal

@KumaresanPerumal Wikipedia เก็บรายชื่อชื่อเขตเวลานี้ไว้ อาจล้าสมัยเล็กน้อย เท่าที่ฉันรู้อินเดียทั้งหมดใช้เขตเวลาAsia/Kolkataปัจจุบันโดยมีค่าชดเชย +05: 30 ในรหัส ZoneId.of( "Asia/Kolkata" )Java: สำหรับข้อมูลเพิ่มเติมและประวัติดูวิกิพีเดีย, เวลาในอินเดีย
Basil Bourque

4

ทางออกที่ยืดหยุ่น

สิ่งนี้จะใช้ได้กับโครงร่างหมายเลขสัปดาห์ใด ๆ ที่สามารถแสดงในWeekFieldsวัตถุได้

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());
    }
}

แนวคิดคือการค้นหาหมายเลขสัปดาห์ของสัปดาห์สุดท้ายของปี ฉันลองครั้งแรกกับ 31 ธันวาคม แต่อาจเป็นในสัปดาห์แรกของปีถัดไป ถ้าเป็นเช่นนั้นฉันจะกลับไปหนึ่งสัปดาห์

ฉันทดสอบอย่างละเอียดด้วยWeekFields.ISOไม่มากกับWeekFieldsวัตถุอื่น ๆแต่อย่างที่ฉันพูดฉันเชื่อว่ามันใช้งานได้

หากคุณทราบความจริงว่าคุณจะต้องISO 8601สัปดาห์ที่ผ่านมาผมคิดว่าคุณควรจะไปกับหนึ่งในคำตอบที่ดีโดยการกวาดและโดยเพรา Bourque ฉันโพสต์สิ่งนี้ในกรณีที่คุณต้องการโซลูชันที่ยืดหยุ่นมากขึ้นซึ่งจะทำงานร่วมกับแผนการกำหนดหมายเลขสัปดาห์อื่น

ใช้ java.time

รหัสในคำถามของคุณเป็นเรื่องตลกที่มันนำเข้าคลาสทั้งจาก Joda-Time และจาก java.time แต่ใช้เก่าCalendarและGregorianCalendarจาก Java 1.1 คลาสเหล่านี้ได้รับการออกแบบมาไม่ดีและล้าสมัยไปแล้วคุณไม่ควรใช้ Joda-Time อยู่ในโหมดบำรุงรักษา, java.time ได้เข้าครอบครองหลังจากนั้น ฉันใช้อะไรและแนะนำให้คุณใช้


1

ฉันคิดว่ามันน่าจะใช้ได้ดีเช่นกัน:

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);

ความคิดที่ดี. มันให้ผลลัพธ์ที่ถูกต้องในปี 2020 (53 สัปดาห์) เช่นเดียวกับ 2019 และ 2021 (แต่ละ 52 สัปดาห์) มันอาจเป็นเรื่องยากเล็กน้อยที่จะโน้มน้าวใจตัวเอง
Ole VV

ดูเหมือนว่าจะให้เวลา 53 สัปดาห์สำหรับการก้าวกระโดดทุกปีซึ่งไม่ถูกต้อง
Ole VV

@ OleV.V อืมยุติธรรมพอ ฉันอยากรู้ว่าการคำนวณของ LocalDate ทำงานอย่างไรภายใต้ประทุน Stupid Earth และรอบเวลาไม่สมบูรณ์เล็กน้อยทำให้สิ่งต่าง ๆ ซับซ้อนเกินกว่าที่พวกมันจะเป็น
ทิมฮันเตอร์


0

หลังจากลองใช้งานจาวาเป็นอย่างมากฉันไม่พบวิธีแก้ปัญหา ฉันเตรียมวันที่และเวลาของ Joda มันให้คำตอบที่ดีอย่างที่ฉันคาดไว้

รหัส:

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

การพึ่งพา Maven:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.5</version>
</dependency>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.