我想添加一定数量的小时,忽略周末
例如,
(星期五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 :(得分:3)
逐步增加小时数而不是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();
}
答案 1 :(得分:1)
我强烈建议您使用JodaTime
(或DateTime
Java8),因为旧的日期/日历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();
}
代码说明:
此代码不支持延长数周的任务,但这是一个可以修改以支持此功能的开始..可能是一些处理不好的边缘情况,我会留给您彻底测试它
答案 2 :(得分:1)
您正在使用旧的日期时间类,这些类已被证明设计糟糕,令人困惑且麻烦。避免它们。
使用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 );
我也从&#34; the weekend&#34;对于任何一组星期值而不是硬编码星期六和星期六星期日。 java.time类包含一个方便的enum,DayOfWeek
- 比在代码中使用字符串或数字要好得多。
Java中的枚举工具比大多数语言中的简单数字掩码一样灵活得多。它的功能之一是一个特殊的Set
实现EnumSet
,用于收集枚举定义的可能项的子集。对于我们这里,我们想收集一对项目,包括星期六项目和星期日项目。
EnumSet<DayOfWeek> daysOfWeek = EnumSet.of ( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY );
也许工作日是一个为期四天的工作日,如周一至周二加周四至周五,然后使用EnumSet.of ( DayOfWeek.WEDNESDAY , DayOfWeek.SATURDAY , DayOfWeek.SUNDAY )
。
现在我们准备调用我们的计算方法了。传递三个论点:
ZonedDateTime
Duration
EnumSet
件DayOfWeek
件。我们收回计算的未来日期时间。
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:[SATURDAY,SUNDAY]是zdtLater:2016-01-05T18:00-05:00 [美国/蒙特利尔]
答案 3 :(得分: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();
}
答案 4 :(得分:0)
基本上你需要做的是首先计算一周剩余的小时数(这是当前时间与周五24:00之间的差异)。如果小时数小于您刚添加的小时数。
否则你从小时中减去该数量,然后如果余数超过120小时(一周),你取整数商并跳过那么多周。最后,将剩余部分添加到当周00:00 @周一。
在你的例子中,你的开始时间是在你的开始时间和24:00 @ Fri 6h之间,这个时间不到48小时,所以你从中减去6h并得到42h。现在42小时不到120小时,所以你不要错过几周,然后在星期一晚上18点到达星期五00:00加上42小时。
答案 5 :(得分: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();
}
答案 6 :(得分:-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();
}