java设置周末不可选_java - 如何考虑不增加周末而将营业时间添加到Date? -Java - 堆栈内存溢出...

避免使用旧的日期时间类

您使用的是旧的日期时间类,事实证明它们设计得不好,令人困惑且麻烦。 避免他们。

java.time

使用Java 8和更高版本中内置的java.time框架。 请参阅教程 。 对于Java 6和7,请使用ThreeTen-Backport项目。 对于Android,该端口的改编ThreeTenABP 。

这是一些示例代码,助您一臂之力。 我只是临时性地鞭打了它,因此它可能并不健壮。 这段代码似乎确实适合您的一个示例用法:

(星期五18:00)+ 48 =(星期二18:00)(星期六和星期日被忽略)

我对此代码进行了概括。 它无需花费数小时,而是需要任何时间跨度的Duration时间(内部表示为总秒数加上几分之一秒,以纳秒为单位)。 您会注意到toString方法的输出在48小时的示例时间内使用了标准的ISO 8601表示法,例如PT48H 。

假设您想要时间线上的真实时刻,我们需要使用时区来解决诸如夏令时(DST)之类的异常。 为此,我们需要从ZonedDateTime开始,该时间将UTC( Instant )中的时间轴上的时刻与时区( ZoneId )相结合。

我们还传递了持续时间(例如48小时)以及一组星期几(例如周六和周日)值。 跳过此方法可以在下面讨论这些类型。

这种方法的策略是占用我们的时间(例如48小时),并一天只减少一天的时间,直到第二天开始。 如果第二天碰巧是一个禁止的星期几,那么我们会滑动到该日期之后的第二天,并继续滑动直到达到允许的(非禁止的)星期几日期。 我们继续蚕食剩余时间,直到达到零。 阅读代码中的注释以进行更多讨论。

在计算第二天的开始时间时,请勿假设一天中的时间为00:00:00.0 。 由于夏时制(DST)以及某些时区中的其他异常,一天可能在其他时间开始。 我们调用atStartOfDay来让java.time确定一天的第一时刻。

public ZonedDateTime addDurationSkippingDaysOfWeek ( ZonedDateTime zdt , Duration duration , EnumSet 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 );

我还从“ 周末 ”推广到任何星期几值,而不是对周六和周日进行硬编码。 java.time类包含一个方便的枚举 DayOfWeek ,比在我们的代码中使用字符串或数字好得多。

Java中的枚举功能比大多数语言中的简单数字常量化常量更灵活和有用。 它的功能之一是特殊的Set实现EnumSet用于当您希望收集枚举定义的可能项的子集时。 对于我们这里,我们要为星期六和星期日收集一对物品。

EnumSet 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:[星期六,周日]是zdt后:2016-01-05T18:00-05:00 [美国/蒙特利尔]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值