簡體   English   中英

獲取兩個日期之間的周數。

[英]Get the number of weeks between two Dates.

我在一個項目中工作,我在日期中有兩種類型。 我想計算這兩個日期之間的周數。 日期可以在不同的年份。 對此有什么好的解決方案嗎?

我試圖用其他主題中建議的 Joda-time 來實現這一點。

我不熟悉這個庫,但我試着做這樣的事情:

public static int getNumberOfWeeks(Date f, Date l){
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    c1.setTime(f);
    c2.setTime(l);
    DateTime start = new DateTime(c1.YEAR, c1.MONTH, c1.DAY_OF_MONTH, 0, 0, 0, 0);
    DateTime end   = new DateTime(c2.YEAR, c2.MONTH, c2.DAY_OF_MONTH, 0, 0, 0, 0);
    Interval interval = new Interval(start, end);
    Period p = interval.toPeriod();
    return p.getWeeks();
}

但這是完全錯誤的......有什么建議嗎?

使用joda time很容易:

DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);

int weeks = Weeks.weeksBetween(dateTime1, dateTime2).getWeeks();

更新答案以解釋 Java 8

// TechTrip - ASSUMPTION d1 is earlier than d2
// leave that for exercise
public static long getFullWeeks(Calendar d1, Calendar d2){

    Instant d1i = Instant.ofEpochMilli(d1.getTimeInMillis());
    Instant d2i = Instant.ofEpochMilli(d2.getTimeInMillis());

    LocalDateTime startDate = LocalDateTime.ofInstant(d1i, ZoneId.systemDefault());
    LocalDateTime endDate = LocalDateTime.ofInstant(d2i, ZoneId.systemDefault());

    return ChronoUnit.WEEKS.between(startDate, endDate);
}

tl;博士

ChronoUnit
.WEEKS
.between(
    myJavaUtilDate_Start.toInstant().atZone( ZoneId.of( "Asia/Tokyo" ) ) , 
    myJavaUtilDate_Stop.toInstant().atZone( ZoneId.of( "Asia/Tokyo" ) ) 
)

7

時間

java.time框架內置於 Java 8 及更高版本中。 這些新類取代了與最早版本的 Java 捆綁在一起的舊日期時間類。

java.time類還取代了非常成功的Joda-Time框架。 java.timeJoda-Time都由Stephen Colbourne領導。

Java 中的日期時間類型表,現代和傳統

Instant替換java.util.Date

現代類Instant替換了遺留類java.util.Date 兩者都代表 UTC 中的一個時刻,即時間線上的一個特定點。 自 UTC 中 1970 年第一時刻的同一紀元參考 1970-01-01T00:00Z 起,兩者在內部都使用計數。 舊類使用毫秒計數,而Instant使用更精細的納秒計數。

要進行轉換,請調用添加到舊類中的新方法。

Instant start = myJavaUtilDateStart.toInstant() ;
Instant stop = myJavaUtilDateStop.toInstant() ;

讓我們用一些示例值來具體說明。

Instant start = OffsetDateTime.of( 2020 , 1 , 23 , 15 , 30 , 0 , 0 , ZoneOffset.UTC ).toInstant();
Instant stop = OffsetDateTime.of( 2020 , 1 , 23 , 15 , 30 , 0 , 0 , ZoneOffset.UTC ).plusWeeks(7 ).toInstant();

時刻與日期

我們的兩個Instant對象都代表一個時刻。 目標是計算周數。 Weeks 表示天,days 表示日歷上的某些日期。

所以我們有點不匹配。 對於任何給定時刻,日期在全球各地因時區而異。 法國巴黎午夜過后的幾分鍾是一個新的約會。 與此同時,在魁北克省蒙特利爾,落后幾個小時,同一時刻仍然是“昨天”,也就是日歷上的前一天。 所以我們不能直接從一對矩計算周數。

您必須首先確定您希望為那些時刻感知日歷的時區。

Continent/Region格式指定正確的時區名稱,例如America/MontrealAfrica/CasablancaPacific/Auckland 永遠不要使用ESTIST等 2-4 個字母的縮寫,因為它們不是真正的時區,不是標准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ; 

ZonedDateTime

將此ZoneId應用於我們的Instant對象以調整到時區,產生一對ZonedDateTime對象。

ZonedDateTime startZdt = start.atZone( z ) ;
ZonedDateTime stopZdt = stop.atZone( z ) ;

ChronoUnit.WEEKS

現在我們可以使用ChronoUnit枚舉來計算經過的周數。

長周 = ChronoUnit.WEEKS.between( startZdt , stopZdt );

轉儲到控制台。

System.out.println( "start.toString() = " + start );
System.out.println( "stop.toString() = " + stop );
System.out.println( "startZdt.toString() = " + startZdt );
System.out.println( "stopZdt.toString() = " + stopZdt );
System.out.println( "weeksCount: " + weeksCount );

查看此代碼在 IdeOne.com 上實時運行

start.toString() = 2020-01-23T15:30:00Z

stop.toString() = 2020-03-12T15:30:00Z

startZdt.toString() = 2020-01-23T10:30-05:00[美國/蒙特利爾]

stopZdt.toString() = 2020-03-12T11:30-04:00[美國/蒙特利爾]

周數:7

三十額外

ThreeTen-Extra項目為 Java 8 及更高版本中內置的java.time框架添加了功能。

Weeks

該項目包括一個Weeks類來表示周數。 它不僅可以計算,還可以在您的代碼中用作類型安全對象。 這種使用還有助於使您的代碼自文檔化。

您可以通過使用Weeks.between方法提供一對時間點來實例化。 這些時間點可以是任何實現java.time.temporal.Temporal 的東西,包括InstantLocalDateOffsetDateTimeZonedDateTimeYearYearMonth等等。

你的java.util.Date對象可以很容易地轉換為Instant對象,時間軸上的時刻以 UTC 為單位,分辨率為納秒。 查看添加到舊日期時間類的新方法。 要從 Date 轉到 Instant,請調用java.util.Date::toInstant

Weeks weeks = Weeks.between( startZdt , stopZdt );

您可以詢問周數。

int weeksNumber = weeks.getAmount(); // The number of weeks in this Weeks object.

您還可以做更多的事情。

生成標准ISO 8601格式的字符串。 P標志着開始。 W表示周數。

PW7


關於java.time

java.time框架內置於 Java 8 及更高版本中。 這些類取代麻煩的老傳統日期時間類,如java.util.DateCalendar ,和SimpleDateFormat

要了解更多信息,請參閱Oracle 教程 並在 Stack Overflow 上搜索許多示例和解釋。 規范是JSR 310

現在處於維護模式Joda-Time項目建議遷移到java.time類。

您可以直接與您的數據庫交換java.time對象。 使用符合JDBC 4.2或更高版本的JDBC 驅動程序 不需要字符串,不需要java.sql.*類。

從哪里獲得 java.time 類?

哪個 java.time 庫與哪個版本的 Java 或 Android 一起使用的表

ThreeTen-Extra項目用額外的類擴展了 java.time。 該項目是未來可能添加到 java.time 的試驗場。 您可以在這里找到一些有用的類,比如IntervalYearWeekYearQuarter ,和更多

java.util.Calendar使用日期算法:

public static int getWeeksBetween (Date a, Date b) {

    if (b.before(a)) {
        return -getWeeksBetween(b, a);
    }
    a = resetTime(a);
    b = resetTime(b);

    Calendar cal = new GregorianCalendar();
    cal.setTime(a);
    int weeks = 0;
    while (cal.getTime().before(b)) {
        // add another week
        cal.add(Calendar.WEEK_OF_YEAR, 1);
        weeks++;
    }
    return weeks;
}

public static Date resetTime (Date d) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(d);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
}

如果您的要求是開始日期是 2020 年 4 月 3 日,結束日期是 2020 年 4 月 7 日。 兩個日期之間相差 4 天。 現在,您可以使用以下代碼段將兩個日期之間的周數設為 1

ChronoUnit.WEEKS.between(LocalDate startDate, LocalDate endDate);

但是,如果您的要求是 03-Apr-2020 在一周內,而 07-Apr-2020 在另一周內,因此您希望兩個日期之間的周數為 2 ,則可以使用以下代碼段。

LocalDate actualStartDate=...
LocalDate actualEndDate=...

LocalDate startDate = actualStartDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY)) 

LocalDate endDate = actualEndDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SATURDAY)) 

long daysBetweenTwoDates = ChronoUnit.DAYS.between(startDate, endDate);
int numberOfWeeks =  (int)Math.ceil(daysBetweenTwoDates/7.0);

在 Java 1.8 中測試

Calendar a = new GregorianCalendar(2002,1,22);
    Calendar b = new GregorianCalendar(2002,1,28);
    System.out.println(a.get(Calendar.WEEK_OF_YEAR));
    System.out.println(b.get(Calendar.WEEK_OF_YEAR)); 
   int weeks = b.get(Calendar.WEEK_OF_YEAR)-a.get(Calendar.WEEK_OF_YEAR);
    System.out.println(weeks);

試試這個必須工作

    Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(2007, 01, 10);
calendar2.set(2007, 07, 01);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
int diffWeeks = (int)diff / (7*24 * 60 * 60 * 1000);

如果您想要確切的完整周數,請使用以下方法,其中結束日期是唯一的:

public static long weeksBetween(Date date1, Date date2) {
    return WEEKS.between(date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
        date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
  }

如果您想要此的 ceil 版本,請使用以下內容:

public static long weeksBetween(Date date1, Date date2) {
    long daysBetween = DAYS.between(date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
        date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()) + 1;
    return daysBetween / 7 + (daysBetween % 7 == 0 ? 0 : 1);
  }

這是我編寫的 2 種不基於外部庫的方法。
第一種方法是星期一是一周的第一天。
第二種方法是星期日是一周的第一天。

請閱讀代碼中的注釋,可以選擇返回兩個日期之間的完整周數,
以及兩個日期之前和之后剩余天數的分數。

public static int getNumberOfFullWeeks(LocalDate startDate,LocalDate endDate)
{
    int dayBeforeStartOfWeek = 0;
    int daysAfterLastFullWeek = 0;

    if(startDate.getDayOfWeek() != DayOfWeek.MONDAY)
    {
        // get the partial value before loop starting
        dayBeforeStartOfWeek = 7-startDate.getDayOfWeek().getValue() + 1;
    }

    if(endDate.getDayOfWeek() != DayOfWeek.SUNDAY)
    {
        // get the partial value after loop ending
        daysAfterLastFullWeek = endDate.getDayOfWeek().getValue();
    }

    LocalDate d1 = startDate.plusDays(dayBeforeStartOfWeek); // now it is the first day of week;
    LocalDate d2 = endDate.minusDays(daysAfterLastFullWeek); // now it end in the last full week

    // Count how many days there are of full weeks that start on Mon and end in Sun
    // if the startDate and endDate are less than a full week the while loop
    // will not iterate at all because d1 and d2 will be the same date
    LocalDate looper = d1;
    int counter = 1;
    while (looper.isBefore(d2))
    {
        counter++;
        looper = looper.plusDays(1);
    }

    // Counter / 7 will always be an integer that will represents full week
    // because we started to count at Mon and stop counting in Sun
    int fullWeeks = counter / 7;

    System.out.println("Full weeks between dates: "
            + fullWeeks + " Days before the first monday: "
            + dayBeforeStartOfWeek + " "
            + " Days after the last sunday: " + daysAfterLastFullWeek);
    System.out.println(startDate.toString() + " - " + endDate.toString());

    // You can also get a decimal value of the full weeks plus the fraction if the days before
    // and after the full weeks
    float full_weeks_decimal = (float)fullWeeks;
    float fraction = ((float)dayBeforeStartOfWeek + (float)daysAfterLastFullWeek) / 7.0F;
    System.out.println("Full weeks with fraction: " + String.valueOf(fraction + full_weeks_decimal));

    return fullWeeks;
}

public static int getNumberOfFullWeeks_WeekStartAtSunday(LocalDate startDate,LocalDate endDate)
{
    int dayBeforeStartOfWeek = 0;
    int daysAfterLastFullWeek = 0;

    if(startDate.getDayOfWeek() != DayOfWeek.SUNDAY)
    {
        // get the partial value before loop starting
        dayBeforeStartOfWeek = 7-getDayOfWeekBySundayIs0(startDate.getDayOfWeek()) + 1;
    }

    if(endDate.getDayOfWeek() != DayOfWeek.SATURDAY)
    {
        // get the partial value after loop ending
        daysAfterLastFullWeek = 1+getDayOfWeekBySundayIs0(endDate.getDayOfWeek());
    }

    LocalDate d1 = startDate.plusDays(dayBeforeStartOfWeek); // now it is the first day of week;
    LocalDate d2 = endDate.minusDays(daysAfterLastFullWeek); // now it end in the last full week

    // Count how many days there are of full weeks that start on Sun and end in Sat
    // if the startDate and endDate are less than a full week the while loop
    // will not iterate at all because d1 and d2 will be the same date
    LocalDate looper = d1;
    int counter = 1;
    while (looper.isBefore(d2))
    {
        counter++;
        looper = looper.plusDays(1);
    }

    // Counter / 7 will always be an integer that will represents full week
    // because we started to count at Sun and stop counting in Sat
    int fullWeeks = counter / 7;

    System.out.println("Full weeks between dates: "
            + fullWeeks + " Days before the first sunday: "
            + dayBeforeStartOfWeek + " "
            + " Days after the last saturday: " + daysAfterLastFullWeek);
    System.out.println(startDate.toString() + " - " + endDate.toString());

    // You can also get a decimal value of the full weeks plus the fraction if the days before
    // and after the full weeks
    float full_weeks_decimal = (float)fullWeeks;
    float fraction = ((float)dayBeforeStartOfWeek + (float)daysAfterLastFullWeek) / 7.0F;
    System.out.println("Full weeks with fraction: " + String.valueOf(fraction + full_weeks_decimal));

    return fullWeeks;
}

   public static int getDayOfWeekBySundayIs0(DayOfWeek day)
    {
        if(day == DayOfWeek.SUNDAY)
        {
            return 0;
        }
        else
        {
            // NOTE: getValue() is starting to count from 1 and not from 0
            return  day.getValue();
        }
    }

Joda Time 計算具有兩個日期的周數,這在某些情況下可能不符合我們的要求。 我有一個 Joda Time 方法來計算兩個日期之間的自然周數。 希望它可以幫助你。 如果你不使用 Joda Time,你可以用 Calendar 修改代碼來做同樣的事情。

//Unlike Joda Time Weeks.weeksBetween() that returns whole weeks computed
//from duration, we return natural weeks between two dates based on week of year
public static int weeksBetween(ReadablePartial date1, ReadablePartial date2) {
    int comp = date1.compareTo(date2);
    if (comp == 0) {
        return 0;
    }

    if (comp > 0) {
        ReadablePartial mid = date2;
        date2 = date1;
        date1 = mid;
    }

    int year1 = date1.get(DateTimeFieldType.weekyear());
    int year2 = date2.get(DateTimeFieldType.weekyear());

    if (year1 == year2) {
        return date2.get(DateTimeFieldType.weekOfWeekyear()) - date1.get(DateTimeFieldType.weekOfWeekyear());
    }

    int weeks1 = 0;

    LocalDate lastDay1 = new LocalDate(date1.get(DateTimeFieldType.year()), 12, 31);
    if (lastDay1.getWeekyear() > year1) {
        lastDay1 = lastDay1.minusDays(7);
        weeks1++;
    }

    weeks1 += lastDay1.getWeekOfWeekyear() - date1.get(DateTimeFieldType.weekOfWeekyear());

    int midWeeks = 0;
    for (int i = year1 + 1; i < year2; i++) {
        LocalDate y1 = new LocalDate(i, 1, 1);
        int yearY1 = y1.getWeekyear();
        if (yearY1 < i) {
            y1 = y1.plusDays(7);
            midWeeks++;
        }

        LocalDate y2 = new LocalDate(i, 12, 31);
        int yearY2 = y2.getWeekyear();
        if (yearY2 > i) {
            y2 = y2.minusDays(7);
            midWeeks++;
        }

        midWeeks += y2.getWeekOfWeekyear() - y1.getWeekOfWeekyear();
    }

    int weeks2 = 0;
    LocalDate firstDay2 = new LocalDate(date2.get(DateTimeFieldType.year()), 1, 1);
    if (firstDay2.getWeekyear() < firstDay2.getYear()) {
        firstDay2 = firstDay2.plusDays(7);
        weeks2++;
    }
    weeks2 += date2.get(DateTimeFieldType.weekOfWeekyear()) - firstDay2.getWeekOfWeekyear();

    return weeks1 + midWeeks + weeks2;
}
    int startWeek = c1.get(Calendar.WEEK_OF_YEAR);
    int endWeek = c2.get(Calendar.WEEK_OF_YEAR);    

    int diff = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);

    int deltaYears = 0;
    for(int i = 0;i < diff;i++){
        deltaYears += c1.getWeeksInWeekYear();
        c1.add(Calendar.YEAR, 1);        
    }
    diff = (endWeek + deltaYears) - startWeek;

包括年份差異。 這對我有用:)

private int weeksBetween(Calendar startDate, Calendar endDate) {
    startDate.set(Calendar.HOUR_OF_DAY, 0);
    startDate.set(Calendar.MINUTE, 0);
    startDate.set(Calendar.SECOND, 0);
    int start = (int)TimeUnit.MILLISECONDS.toDays(
        startDate.getTimeInMillis())
        - startDate.get(Calendar.DAY_OF_WEEK);
    int end = (int)TimeUnit.MILLISECONDS.toDays(
        endDate.getTimeInMillis());
    return (end - start) / 7;
}

如果此方法返回 0,則它們在同一周

如果此方法返回 1 endDate 是 startDate 之后的一周

如果此方法返回 -1 endDate 是 startDate 之前的一周

你明白了

在不使用 JodaTime 的情況下,我能夠准確計算兩個日歷之間的周數(包括閏年等)

private fun calculateNumberOfWeeks() {
    val calendarFrom = Calendar.getInstance()
    calendarFrom.set(Calendar.HOUR_OF_DAY, 0)
    calendarFrom.set(Calendar.MINUTE, 0)
    calendarFrom.set(Calendar.SECOND, 0)
    calendarFrom.set(Calendar.MILLISECOND, 0)

    val calendarTo = Calendar.getInstance()
    calendarTo.add(Calendar.MONTH, months)
    calendarTo.set(Calendar.HOUR_OF_DAY, 0)
    calendarTo.set(Calendar.MINUTE, 0)
    calendarTo.set(Calendar.SECOND, 0)
    calendarTo.set(Calendar.MILLISECOND, 0)

    var weeks = -1
    while (calendarFrom.timeInMillis < calendarTo.timeInMillis) {
        calendarFrom.add(Calendar.DATE, 7)
        weeks++
        Log.d(Constants.LOG_TAG, "weeks $weeks")
    }
}

簡單的方法

  Calendar cal1 = new GregorianCalendar();
    Calendar cal2 = new GregorianCalendar();
    cal1.set(2014, 3, 3);
    cal2.set(2015, 3, 6);

    weekscount.setText("weeks= "+ ( (cal2.getTime().getTime() - cal1.getTime().getTime()) / (1000 * 60 * 60 * 24))/7);

這是查找兩個日期之間的周數的簡單方法。

SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String classStartData = "31 01 2021";
String classEndData = "08 03 2021";

Date dateClassStart = myFormat.parse(classStartData);
Date dateClassEnd = myFormat.parse(classEndData);

long differenceWeek = dateClassEnd.getTime() - dateClassStart.getTime();
int programLength = (int)(TimeUnit.DAYS.convert(differenceWeek, TimeUnit.MILLISECONDS)/7);
System.out.println("Class length in weeks: " +programLength);

在參考了許多解決方案之后,這對我有用。 {前提是我不想使用外部庫}

public static int getNumberOfWeeks(Date date1, Date date2) {
if (date1.after(date2)) {
        return getNumberOfWeeks(date2, date1);
    }

    Date date = date1;
    int days = 0;
    while (date.before(date2)) {
        days++;
        date = addDays(date, 1);
    }
    return days/7;
}

向日期添加天數:

Date addDays(Date date, int days) {
    if (days == 0) {
        return date;
    } else {
        Date shiftedDate = new Date(date.getTime() + (long)days * 86400000L);
        return shiftedDate;
    }
}

您可以通過以下方式進行:

// method header not shown
// example dates:
f = new GregorianCalendar(2009,Calendar.AUGUST,1);
l = new GregorianCalendar(2010,Calendar.SEPTEMBER,1);
DateTime start = new DateTime(f);
DateTime end = new DateTime(l);
// Alternative to above - example dates with joda:
// DateTime start = new DateTime(2009,8,1,0,0,0,0);
// DateTime end = new DateTime(2010,9,1,0,0,0,0);
Interval interval = new Interval(start,end);
int weeksBetween = interval.toPeriod(PeriodType.weeks()).getWeeks();
// return weeksBetween;

這應該給你一個 int 代表兩個日期之間的周數。

public int diffInWeeks(Date start, Date end) { long diffSeconds = (end.getTime() - start.getTime())/1000; return (int)diffSeconds/(60 * 60 * 24 * 7); }

看看下面的文章: Java - 計算兩個日期之間的差異

daysBetween 方法將允許您獲取日期之間的天數。 然后你可以簡單地除以 7 得到完整的周數。

        Calendar date1 = Calendar.getInstance();
        Calendar date2 = Calendar.getInstance();

        date1.clear();
        date1.set(datePicker1.getYear(), datePicker1.getMonth(),
                datePicker1.getDayOfMonth());
        date2.clear();
        date2.set(datePicker2.getYear(), datePicker2.getMonth(),
                datePicker2.getDayOfMonth());

        long diff = date2.getTimeInMillis() - date1.getTimeInMillis();

        float dayCount = (float) diff / (24 * 60 * 60 * 1000);

        int week = (dayCount / 7) ;

希望這可以幫助你

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM