查看当前时间是否在当前Java的特定时间范围内

我确信这在1000个不同的地方完成了1000次。 问题是我想知道是否有更好的/标准/更快的方法来检查当前“时间”是否在以hh:mm:ss格式给出的两个时间值之间。 例如,我的大型业务逻辑不应该在18:00:00 and 18:30:00之间运行。 所以这就是我的想法:

  public static boolean isCurrentTimeBetween(String starthhmmss, String endhhmmss) throws ParseException{ DateFormat hhmmssFormat = new SimpleDateFormat("yyyyMMddhh:mm:ss"); Date now = new Date(); String yyyMMdd = hhmmssFormat.format(now).substring(0, 8); return(hhmmssFormat.parse(yyyMMdd+starthhmmss).before(now) && hhmmssFormat.parse(yyyMMdd+endhhmmss).after(now)); } 

示例测试用例:

  String doNotRunBetween="18:00:00,18:30:00";//read from props file String[] hhmmss = downTime.split(","); if(isCurrentTimeBetween(hhmmss[0], hhmmss[1])){ System.out.println("NOT OK TO RUN"); }else{ System.out.println("OK TO RUN"); } 

我正在寻找的是更好的代码

  • 在表现
  • 在外表
  • 在正确性

我不想要的

  • 第三方图书馆
  • exception处理辩论
  • 变量命名约定
  • 方法修饰符问题

这就是你应该做的所有事情,这个方法与输入松散耦合,高度连贯。

 boolean isNowBetweenDateTime(final Date s, final Date e) { final Date now = new Date(); return now.after(s) && now.before(e); } 

如何获得开始和结束的Date对象与比较它们无关。 通过传递String表示,你使事情变得比你需要的更复杂。

这是一个更好的方式来获得开始和结束日期,再次松散耦合和高度连贯。

 private Date dateFromHourMinSec(final String hhmmss) { if (hhmmss.matches("^[0-2][0-9]:[0-5][0-9]:[0-5][0-9]$")) { final String[] hms = hhmmss.split(":"); final GregorianCalendar gc = new GregorianCalendar(); gc.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hms[0])); gc.set(Calendar.MINUTE, Integer.parseInt(hms[1])); gc.set(Calendar.SECOND, Integer.parseInt(hms[2])); gc.set(Calendar.MILLISECOND, 0); return gc.getTime(); } else { throw new IllegalArgumentException(hhmmss + " is not a valid time, expecting HH:MM:SS format"); } } 

现在,您可以进行两个命名良好的方法调用,这些调用将非常自我记录。

正如凯文所指出的,模糊棒棒糖的正则表达式不会在14:00到19:00之间接收。

要获得完整的24小时比赛,您可以使用:

 if (hhmmss.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { // Do stuff here } 

以下类是我刚刚从其他答案的一些代码中创建的。 它封装了“时间段”的行为,与特定日期无关。 我们的系统使用此类来检查当前时间是否在我们指定的维护窗口之内。 即05:00:00至07:00:00

 import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * * @author Adam Yocum */ public class ExclusionTimePeriod { private String timeStart; private String timeEnd; /** * @return the timeStart */ public String getTimeStart() { return timeStart; } /** * @param timeStart the timeStart to set */ public void setTimeStart(String timeStart) { if (timeStart.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { this.timeStart = timeStart; } else { throw new IllegalArgumentException(timeStart + " is not a valid time, expecting HH:MM:SS format"); } } /** * @return the timeEnd */ public String getTimeEnd() { return timeEnd; } /** * @param timeEnd the timeEnd to set */ public void setTimeEnd(String timeEnd) { if (timeEnd.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$")) { this.timeEnd = timeEnd; } else { throw new IllegalArgumentException(timeEnd + " is not a valid time, expecting HH:MM:SS format"); } } private Date toDate(String hhmmss){ final String[] hms = hhmmss.split(":"); final GregorianCalendar gc = new GregorianCalendar(); gc.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hms[0])); gc.set(Calendar.MINUTE, Integer.parseInt(hms[1])); gc.set(Calendar.SECOND, Integer.parseInt(hms[2])); gc.set(Calendar.MILLISECOND, 0); Date date = gc.getTime(); return date; } public boolean isNowInPeriod() { final Date now = new Date(); return now.after(toDate(getTimeStart())) && now.before(toDate(getTimeEnd())); } public static void main(String[] args){ //Test All possible hours for(int hour=0;hour<=23;hour++){ String hourStr = ""; if(hour<=9){ hourStr = "0"+hour; }else{ hourStr = ""+hour; } for(int min=0;min<60;min++){ String minStr = ""; if(min<=9){ minStr = "0"+min; }else{ minStr = ""+min; } for(int sec=0;sec<60;sec++){ String secStr = ""; if(sec<=9){ secStr = "0"+sec; }else{ secStr = ""+sec; } String hhmmss = hourStr+":"+minStr+":"+secStr; ExclusionTimePeriod period = new ExclusionTimePeriod(); period.setTimeStart(hhmmss); period.setTimeEnd(hhmmss); System.out.println(hhmmss+" Ok"); } } } //Test isInPeriod functionality ExclusionTimePeriod isInTest = new ExclusionTimePeriod(); isInTest.setTimeStart("10:00:00"); isInTest.setTimeEnd("10:43:00"); System.out.println((new Date())+" is between "+isInTest.getTimeStart()+" and "+isInTest.getTimeEnd()+" = "+isInTest.isNowInPeriod()); } } 

dateFromHourMinSec方法有缺陷。 它不允许任何小时数大于3的小时,例如18:00:00。 如果将其更改为允许[0-2] [0-9],则允许​​时间为29:00:00。 有解决方法吗?

TL;博士

 LocalTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ) .toLocalTime() ; Boolean isBetween = ( ! now.isBefore( LocalTime.of( 18 , 0 ) ) // "not before" means "is equal to OR after". && now.isBefore( LocalTime.of( 18 , 30 ) ) ; // Half-Open, beginning is *inclusive* while ending is *exclusive*. 

使用java.time

您正在使用旧的日期时间类,这些类已被certificate设计糟糕,令人困惑且麻烦。 它们现在已经遗留下来 ,取而代之的是java.time类。

LocalTime

不要仅仅传递代表时间值的字符串。 我们现在有一个类型, LocalTime类。

 LocalTime start = LocalTime.of( 18 , 0 ); LocalTime stop = LocalTime.of( 18 , 30 ); 

将这些实例传递给您的实用方法。 该方法不应该进行任何解析,因此不需要抛出解析exception。

 public static boolean isCurrentTimeBetween( LocalTime start , LocalTime stop ) { … 

ZonedDateTime

时区对于确定当前日期和时间至关重要。 对于任何给定的时刻,日期在全球范围内因地区而异。 例如, 法国巴黎午夜过后几分钟,在魁北克蒙特利尔的 “昨天”仍然是新的一天。

continent/region的格式指定适当的时区名称 ,例如America/MontrealAfrica/CasablancaPacific/Auckland 。 切勿使用3-4字母缩写,例如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

为了比较现在的时间,我们可以简单地从ZonedDateTime提取ZonedDateTime 。 但我们遇到了exception问题,例如夏令时(DST)和重新定义时区的政治家。 特定日期可能没有任何下午6点的小时。 这个难题的解决方案取决于您的业务环境和业务规则。 您可以忽略这个难题,并坚持询问当前时间是否在您的目标起止时间之间。 或者您可以将时区应用到一天中的开始 – 停止时间,并让ZonedDateTime类根据需要进行调整。 让我们看看这两种方法。

忽略exception

首先,忽略任何exception。 简单地和字面地询问当前时间是否在目标开始和停止时间之间。

我们可以从分区的日期时间对象中提取时间对象。

 LocalTime localTimeNow = zdt.toLocalTime(); // Extract a time-of-day from the zoned date-time object. 

将其与我们的停止开始时间进行比较。 请注意,我们在这里使用半开放方法来定义时间跨度。 在这种方法中,开始是包容性的,而结尾是独占的 。 这种方法在日期工作中很常见,通常是明智的选择。

 Boolean isNowOnOrAfterStart = ( ! localTimeNow.isBefore( start ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before". Boolean isNowBeforeStop = localTimeNow.isBefore( stop ); Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive. 

考虑exception

接下来我们考虑任何exception。 我们将开始和停止时间应用于同一时区内的当前日期。 我们从分区的日期时间对象中提取日期。

 LocalDate localDateToday = zdt.toLocalDate(); ZonedDateTime zdtStart = ZonedDateTime.of( localDateToday , start , z ); ZonedDateTime zdtStop = ZonedDateTime.of( localDateToday , stop , z ); 

研究类文档以了解ZonedDateTime.of在解决无效时间值方面的行为。 没有完美的方法来解决不存在的时间值,因此您必须确定此类的方式是否符合您的业务规则。

ZonedDateTime.of

public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone)

从本地日期和时间获取ZonedDateTime的实例。 这将创建一个与输入本地日期和时间尽可能匹配的分区日期时间。 时区规则(例如夏令时)意味着并非每个本地日期时间对指定区域都有效,因此可以调整本地日期时间。

本地日期时间和第一个组合形成一个本地日期时间。 然后将本地日期时间解析为时间线上的单个瞬间。 这是通过从区域ID的规则定义的本地日期时间中找到UTC / Greenwich的有效偏移量来实现的。

在大多数情况下,本地日期时间只有一个有效偏移量。 在重叠的情况下,当设置回时钟时,存在两个有效的偏移。 该方法使用通常对应于“夏天”的较早偏移。

在间隙的情况下,当时钟向前跳跃时,没有有效的偏移。 相反,将本地日期时间调整为稍后的间隙长度。 对于典型的一小时夏令时变化,本地日期时间将在一小时后移动到通常对应于“夏天”的偏移量。

应用与上面相同的比较逻辑。

 Boolean isNowOnOrAfterStart = ( ! zdt.isBefore( zdtStart ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before". Boolean isNowBeforeStop = zdt.isBefore( zdtStop ); Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive. 

进行比较的另一种方法是使用ThreeTen-Extra项目中方便的Interval类。 该类会消耗Instant对象,您可以从ZonedDateTime对象中提取ZonedDateTime对象。 Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

 Interval interval = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() ); Boolean isNowInTargetZone = interval.contains( zdt.toInstant() ); 

关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。

从哪里获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6SE 7
    • 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
  • Android的
    • ThreeTenABP项目特别适用于Android的ThreeTen-Backport (如上所述)。
    • 请参见如何使用ThreeTenABP ….

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如IntervalYearWeekYearQuarter等。