2016-01-22 72 views
1

我想補充一定數量時到今天爲止,無視週末如何添加營業時間到日期考慮不添加週末? - Java的

例如,

(週五18:00)+ 48 =(Tuseday 18:00)(週六,週日都將被忽略)

,因爲該公司工作24小時,營業時間是24但我仍然不能得到如何只在工作日添加小時

功能可以是這樣的:

public Date getTaskEndTime(Calendar startDate, int hours){ 
    // calculate the end time by adding the hours ignoring the weekends 
} 
+0

您是否必須在週末考慮國家法定節假日?你有沒有做出自己的努力? – skyking

+0

不僅週末(週六和週日)@skyking – MBH

+0

我想你可以檢查一下週末是否重疊(多少次),只需加上n次的X 48' –

回答

2

步驟添加小時沒有更大然後24小時。如果您在星期六或星期日結束,請在每一步後檢查。在每種情況下再添加24小時。這應該做你想做的。

public Date getTaskEndTime(Calendar startDate, int hours){ 
    while (hours > 0){ 
     int step = 0; 
     if(hours > 24) step = 24; 
     else step = hours;   
     hours -= step;   
     startDate.add(Calendar.HOUR_OF_DAY, step);   
     int dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK); 
     if(dayOfWeek == Calendar.SATURDAY) hours += 24; 
     if(dayOfWeek == Calendar.SUNDAY) hours += 24; 
    } 
    return startDate.getTime(); 
} 
+0

的作品就像你創造了我的一天的魅力,我尊重喬達汀是一個好的圖書館,但是當我需要在每個地方都使用它的時候,它是有用的。 dosnt是有意義的,只包含JodaTime Library的這個功能! JodaTime,DateTime和Java 8都不需要。很棒的工作,謝謝 – MBH

0

基本上你需要做的是首先計算一週剩餘的小時數(這是當前時間和24:00 @週五之間的差值)。如果小時數少於剛剛添加的小時數。

否則,您從小時中減去該數額,然後如果餘數大於120h(一週),則取整數商並跳過數週。最後你將剩下的部分添加到那周的00:00 @ Mon。

在您的示例中,您的開始時間爲24:00 @ Fri 6h,即小於48h,因此您從中減去6h並獲得42h。現在42小時不到120小時,所以你不會跳過幾個星期,然後你在週二00:00加入42小時,你將在18:00到達星期二。

-1

你需要處理它的定製方式:

public Date getTaskEndTime(Calendar startDate, int hours) { 
     Calendar endTime = Calendar.getInstance(); 
     endTime.setTime(startDate.getTime()); 
     endTime.add(Calendar.HOUR, hours); // add 2 for saturday and sunday 
     int dayOfWeek = endTime.get(Calendar.DAY_OF_WEEK); 
     if (dayOfWeek == Calendar.SATURDAY) { 
      endTime.add(Calendar.DATE, 2); // add 2 for saturday and sunday 
     } else if (dayOfWeek == Calendar.SATURDAY) { 
      endTime.add(Calendar.DATE, 1); // add 1 for sunday 
     } 
     return endTime.getTime(); 
    } 
+0

如果開始日期是在一個週末不要緊。如果startdate是星期五,並且小時數是40,那麼您需要定製邏輯。 – Tobb

+0

,你已經有2次SUNDAY :) –

+0

我剛剛給出了語法。您可以檢查開始日期或當前日期。 OP需要忽略週末,以便檢查他必須將其放入代碼中。 – Pranalee

1

我會強烈建議使用JodaTime(或Java8的DateTime)這一點,因爲舊的日期/日曆API是好看不中用。

public DateTime getEndtime(final DateTime startdate, final int hours) { 
    final DateTime endOfWeek = endOfWeek(startdate); 

    final Duration restOfWeek = new Duration(startdate, endOfWeek); 

    final Duration hoursDuration = toDuration(hours); 
    if (restOfWeek.isLongerThan(hoursDuration)) { 
     return startdate.plus(hoursDuration); 
    } else { 
     final Duration durationForNextWeek = hoursDuration.minus(restOfWeek); 
     return startOfWeek(startdate).plus(durationForNextWeek); 
    } 
} 

//Converts number of hours as int to Duration 
private Duration toDuration(final int hours) { 
    return new Duration(hours * 60 * 60 * 1000); 
} 

//Returns coming friday, 1 millisecond to midnight 
private DateTime endOfWeek(final DateTime dateTime) { 
    DateTime copy = dateTime; 
    while (copy.getDayOfWeek() != 6) { 
     copy = copy.plusDays(1); 
    } 

    return copy.toDateMidnight().toDateTime().minusMillis(1); 
} 

//Returns the following monday at midnight 
//If dateTime is on a monday, the next monday will be chosen 
private DateTime startOfWeek(final DateTime dateTime) { 
    DateTime copy = dateTime.plusDays(1); 
    while (copy.getDayOfWeek() != 1) { 
     copy = copy.plusDays(1); 
    } 

    return copy.toDateMidnight().toDateTime(); 
} 

解釋代碼:

  • 檢查是否可以在不越界進入週末
  • 如果沒有添加的小時數,只需添加小時的開始日期
  • 如果是,找到要轉移到下週的持續時間,並將其添加到本週的開始日期

此代碼不支持延長多周的任務,但這是一個開始,你可以修改以支持這一點..可能是一些邊緣案例處理不好,我會留給你來徹底測試它。

+0

Joda-Time中的'midnight'相關類和方法已經被棄用,並且他們的使用被強烈阻止。使用['withTimeAtStartOfDay'](http://www.joda.org/joda-time/apidocs/org/joda/time/DateTime.html#withTimeAtStartOfDay--)方法。 –

0

請參考下面的代碼,看看是否有幫助。

public static Date getTaskEndTime(Date startDate, int hours) { 
    // calculate the end time by adding the hours ignoring the weekends 
    Calendar endCal = Calendar.getInstance(); 
    endCal.setTime(startDate); 

    for (int i = 0; i < hours; hours = hours - 8) { 
     if (!(endCal.get(Calendar.DAY_OF_WEEK) == 1 || endCal.get(Calendar.DAY_OF_WEEK) == 7)) { 
      endCal.add(Calendar.DAY_OF_MONTH, 1); 
     } else { 
      endCal.add(Calendar.DAY_OF_MONTH, 1); 
      hours = hours + 8; 
     } 
    } 
    return endCal.getTime(); 
} 
+0

我已將工作時間僅視爲8。這種方法存在一個問題,如果估計的小時數不是工作時間的倍數,那麼它可能會在結束日期之外增加一天。 –

1

避免舊日期,時間類

您使用的是已被證明是設計不良的舊日期時間類,混亂和麻煩。避免它們。

java。時間

使用內置於Java 8及更高版本中的java.time框架。見Tutorial。對於Java 6 & 7,請使用ThreeTen-Backport項目。對於Android,該後端端口的改編,ThreeTenABP

下面是一些示例代碼,讓你去。我只是馬上掀起了這個,所以它可能不健壯。此代碼似乎爲你一個例子使用工作:

(週五18:00)+ 48 =(Tuseday 18:00)(週六,週日被忽略)

我概括這個代碼一點點。而不是幾個小時,在任何時間段(內部表示爲總秒數加上幾分之一秒(納秒))需要Duration。您會注意到toString方法的輸出使用標準的ISO 8601表示法,例如PT48H用於48小時的示例。

假設您想要時間線上的真實時刻,我們需要使用時區來解釋夏令時(DST)等異常情況。爲此,我們需要以ZonedDateTime開頭,其中結合了UTC(Instant)時間軸上的時刻與時區(ZoneId)。

我們還傳遞一個持續時間,如48小時,以及一組週日值,如星期六的星期六&。跳過這個方法來討論下面這些類型。

這種方法的策略是將我們的持續時間例如48小時和芯片一次一天地拿走,以達到第二天開始所需的量。如果第二天恰好是禁止的星期幾,我們就會滑到第二天的那一天,並繼續滑動,直到達到允許的(不禁止的)星期幾日期。我們繼續蠶食我們的剩餘時間,直到達到零。閱讀代碼中的評論以獲得更多討論。

計算第二天的開始時,不要假定時間爲00:00:00.0。由於夏令時(DST)以及某些時區的其他異常情況,該日可能會在另一時間開始。我們呼叫atStartOfDay讓java.time確定一天中的第一個時刻。

public ZonedDateTime addDurationSkippingDaysOfWeek (ZonedDateTime zdt , Duration duration , EnumSet<DayOfWeek> daysOfWeek) { 
    // Purpose: Start at zdt, add duration but skip over entire dates where day-of-week is contained in EnumSet of prohibited days-of-week. For example, skip over United States weekend of Saturday-Sunday. 
    // Verify inputs. 
    if ((null == zdt) || (null == zdt) || (null == zdt)) { 
     throw new IllegalArgumentException ("Passed null argument. Message # bf186439-c4b2-423a-b5c9-76edebd87cf0."); 
    } 
    if (daysOfWeek.size() == DayOfWeek.values().length) { // We must receive 6 or less days. If passed all 7 days of the week, no days left to use for calculation. 
     throw new IllegalArgumentException ("The EnumSet argument specified all days of the week. Count: " + daysOfWeek.size() + ". So, impossible to calculate if we skip over all days. Message # 103a3088-5600-4d4e-a1e0-54410afa14f8."); 
    } 

    // Move through time, day-to-day, allocating remaining duration. 
    ZoneId zoneId = zdt.getZone(); // Passed as argument in code below. 
    ZonedDateTime moment = zdt; // This var is reassigned in loop below to fresh value, later and later, as we allocate the Duration to determine our target date-time. 
    Duration toAllocate = duration; // Loop below chips away at this Duration until none left. 
    while ( ! toAllocate.isZero()) { // Loop while some duration remains to be allocated. 
     if (toAllocate.isNegative()) { // Bad - Going negative should be impossible. Means our logic is flawed. 
      throw new RuntimeException ("The duration to allocate ran into a negative amount. Should not be possible. Message # 15a4267d-c16a-417e-a815-3c8f87af0232."); 
     } 
     ZonedDateTime nextDayStart = moment.toLocalDate().plusDays (1).atStartOfDay (zoneId); 
     Duration untilTomorrow = Duration.between (moment , nextDayStart); 
     // ZonedDateTime oldMoment = moment; // Debugging. 
     Duration allocation = null; 
     if (untilTomorrow.compareTo (toAllocate) >= 0) { // If getting to tomorrow exceeds our remaining duration to allocate, we are done. 
      // Done -- we can allocate the last of the duration. Remaining to allocate is logically zero after this step. 
      moment = moment.plus (toAllocate); 
      allocation = toAllocate; // Allocating all of our remaining duration. 
      // Do not exit here; do not call "return". Code below checks to see if the day-of-week of this date is prohibited. 
     } else { // Else more duration to allocate, so increment to next day. 
      moment = nextDayStart; 
      allocation = untilTomorrow; // Allocating the amount of time to take us to the start of tomorrow. 
     } 
     toAllocate = toAllocate.minus (allocation); // Subtract the amount of time allocated to get a fresh amount remaining to be 
     // Check to see if the moment has a date which happens to be a prohibited day-of-week. 
     while (daysOfWeek.contains (moment.getDayOfWeek())) { // If 'moment' is a date which is a day-of-week on oun prohibited list, move on to the next date. 
      moment = moment.toLocalDate().plusDays (1).atStartOfDay (zoneId); // Move to start of the next day after. Continue loop to check this next day. 
     } 

    } 
    return moment; 
} 

要調用該代碼,我們將使用您的示例數據值。作爲獲取原始數據輸入的一種方式,我們將一個字符串解析爲LocalDateTime

String input = "2016-01-01T18:00:00"; 
LocalDateTime ldt = LocalDateTime.parse (input); 

LocalDateTime對象不代表時間軸上的實際的時刻。所以我們申請一個時區來獲得一個實際的時刻,一個ZonedDateTime

ZoneId zoneId = ZoneId.of ("America/Montreal"); 
ZonedDateTime zdt = ldt.atZone (zoneId); 
Duration duration = Duration.ofHours (48); 

我也是從「the weekend」推廣到任何一組中某一天的周值,而不是硬編碼的週六週日&。 java.time類包括一個方便的enum,DayOfWeek - 比我們的代碼中使用字符串或數字要好得多。

在大多數語言中,Java中的enum工具比簡單的數字屏蔽常量更靈活有用。其特點是當你想收集由你的枚舉定義的可能項目的一個子集時,一個特殊的Set實現EnumSet。對於我們這裏,我們想收集一對物品,爲週六項目和週日項目。

EnumSet<DayOfWeek> daysOfWeek = EnumSet.of (DayOfWeek.SATURDAY , DayOfWeek.SUNDAY); 

也許工作日是四天工作制,如週一,週二加週四,週五,然後使用EnumSet.of (DayOfWeek.WEDNESDAY , DayOfWeek.SATURDAY , DayOfWeek.SUNDAY)

現在,我們準備調用我們的計算方法。傳遞三個參數:

  • 起始ZonedDateTime
  • 一個Duration被添加到起始日期 - 時間
  • DayOfWeek項目的EnumSet

我們回到我們的計算未來的日期,時間。

ZonedDateTime zdtLater = this.addDurationSkippingDaysOfWeek (zdt , duration , daysOfWeek); 

轉儲到控制檯。

System.out.println ("zdt: " + zdt + " plus duration: " + duration + " while skipping daysOfWeek: " + daysOfWeek + " is zdtLater: " + zdtLater); 

ZDT:2016-01-01T18:00-05:00 [美國/蒙特利爾]加持續時間:PT48H同時跳過daysOfWeek:[星期六,星期天]是zdtLater:2016-01-05T18:00 -05:00 [美國/蒙特利爾]

1
下面

代碼確實解決的目的。

public static Date addBusinessHours(Calendar startDate, int hours, int workingHourStart, int workingHourEnd){ 
    System.out.println("Entering: Date Time " + startDate.getTime() + " | Remaining Hours: "+ hours + " | Working hours ("+workingHourStart+"-"+workingHourEnd+")"); 

    if(hours == 0){ 
     return startDate.getTime(); 
    } 
    int hourOfDay = startDate.get(Calendar.HOUR_OF_DAY); 
    if(startDate.get(Calendar.MINUTE) > 0){ 
     hourOfDay = hourOfDay +1; 
    } 

    int dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK); 

    if(dayOfWeek == Calendar.SATURDAY){ 
     startDate.add(Calendar.DATE, 2); 
     startDate.set(Calendar.HOUR_OF_DAY, workingHourStart); 
     startDate.set(Calendar.MINUTE, 0); 
     startDate.set(Calendar.SECOND, 0); 
     addBusinessHours(startDate, hours, workingHourStart, workingHourEnd); 
    } 
    if(dayOfWeek == Calendar.SUNDAY){ 
     startDate.add(Calendar.DATE, 1); 
     startDate.set(Calendar.HOUR_OF_DAY, workingHourStart); 
     startDate.set(Calendar.MINUTE, 0); 
     startDate.set(Calendar.SECOND, 0); 
     addBusinessHours(startDate, hours, workingHourStart, workingHourEnd); 
    } 

    if(dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY){ 
     if(hourOfDay < workingHourStart){ 
      startDate.set(Calendar.HOUR_OF_DAY, workingHourStart); 
      startDate.set(Calendar.MINUTE, 0); 
      startDate.set(Calendar.SECOND, 0); 
      hourOfDay = startDate.get(Calendar.HOUR_OF_DAY); 
      dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK); 
      addBusinessHours(startDate, hours, workingHourStart, workingHourEnd); 
     } 
     else if(hourOfDay >= workingHourEnd){ 

      startDate.add(Calendar.DATE, 1); 
      startDate.set(Calendar.HOUR_OF_DAY, workingHourStart); 
      startDate.set(Calendar.MINUTE, 0); 
      startDate.set(Calendar.SECOND, 0); 
      hourOfDay = startDate.get(Calendar.HOUR_OF_DAY); 
      dayOfWeek = startDate.get(Calendar.DAY_OF_WEEK); 
      addBusinessHours(startDate, hours, workingHourStart, workingHourEnd); 
     } 

     else if(hourOfDay >= workingHourStart && hourOfDay < workingHourEnd){ 
      if(hours+hourOfDay <= workingHourEnd){ 
       startDate.add(Calendar.HOUR_OF_DAY, hours); 
       return startDate.getTime(); 
      }else{ 
       //System.out.println("¤¤" + startDate.getTime()); 
       startDate.add(Calendar.DATE, 1); 
       //System.out.println("¤¤" + startDate.getTime()); 
       startDate.set(Calendar.HOUR_OF_DAY, workingHourStart); 
       startDate.set(Calendar.MINUTE, 0); 
       startDate.set(Calendar.SECOND, 0); 
       //System.out.println("¤¤" + startDate.getTime()); 

       System.out.println("##"+hours+ "##"+ workingHourEnd + "##" + hourOfDay); 
       int remaining_hours = hours - (workingHourEnd - hourOfDay); 
       addBusinessHours(startDate, remaining_hours, workingHourStart, workingHourEnd); 
      } 
     } 
    } 

    return startDate.getTime(); 
}