代码之家  ›  专栏  ›  技术社区  ›  ring bearer

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

  •  10
  • ring bearer  · 技术社区  · 14 年前

    我确信这是在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");
      }
    

    我要找的是更好的代码

    • 在表演中
    • 外观
    • 正确性

    我不想找的东西

    • 第三方图书馆
    • 异常处理辩论
    • 变量命名约定
    • 方法修改器问题
    5 回复  |  直到 14 年前
        1
  •  20
  •   user177800    11 年前

    这就是您所需要做的,这个方法与输入松散耦合,并且高度一致。

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

    如何获得开始和结束的日期对象与比较它们无关。你让事情变得比传球更复杂 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");
        }
    }
    

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

        2
  •  4
  •   Pineechio    14 年前

    正如凯文所指出的,模糊棒棒糖的regex不会在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
    }
    
        3
  •  1
  •   Adam Yocum    12 年前

    下面的课程是我刚从其他答案的一些代码中创建的。它封装了“时间段”的行为,与特定的日期无关。我们的系统正在使用这个类来检查当前时间是否在我们指定的维护窗口中。即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());
    
        }
    }
    
        4
  •  0
  •   Kevin    14 年前

    datefromhourminsec方法在写入时有缺陷。它不允许第二个数字大于3的任何时间,例如18:00:00。如果您将其更改为允许[0-2][0-9],它将允许29:00:00等时间。 有办法解决这个问题吗?

        5
  •  0
  •   Community Egal    7 年前

    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

    您使用的是旧的日期时间类,这些类被证明设计不好、容易混淆并且很麻烦。他们现在是 legacy ,由java.time类替代。

    LocalTime

    不要只传递表示时间值的字符串。我们现在有了一种类型 当地时间 班级。

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

    将这些实例传递给实用工具方法。该方法不必进行任何解析,因此无需引发解析异常。

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

    ZonedDateTime

    时区对于确定当前日期和时间至关重要。在任何一个特定的时刻,日期在全球各地各不相同。例如,在 Paris France 在昨天还是新的一天吗 Montréal Québec .

    指定 proper time zone name 格式为 continent/region ,例如 America/Montreal , Africa/Casablanca ,或者 Pacific/Auckland . 切勿使用3-4字母缩写,如 EST IST 就像他们一样 真正的时区,不标准,甚至不独特!.

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

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

    忽略异常

    首先,忽略任何异常。简单而准确地询问当前时间是否介于目标开始时间和停止时间之间。

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

    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.
    

    考虑异常情况

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

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

    学习课堂文档以了解 ZonedDateTime.of 解析无效的时间值。没有完美的方法来解决不存在的时间值,因此您必须决定这个类方法是否符合您的业务规则。

    分区日期时间

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

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

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

    在大多数情况下,本地日期时间只有一个有效的偏移量。在重叠的情况下,当时钟返回时,有两个有效的偏移。此方法使用通常与“夏季”对应的早期偏移量。

    在间隙的情况下,当时钟向前跳时,没有有效的偏移。相反,本地日期时间会根据间隙的长度进行调整,以使其更晚。对于典型的一小时夏令时更改,本地日期时间将在一小时后移动到通常对应于“夏季”的偏移量中。

    应用与我们上面看到的相同的比较逻辑。

    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.
    

    另一种比较方法是使用 Interval 从threeten额外项目中类。那门课很痛苦 Instant 对象,可以从 分区日期时间 物体。这个 Instant 类表示时间线上的某一时刻 UTC 决议为 nanoseconds (小数点后最多九(9)位)。

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

    关于java.time

    这个 java.time 框架是在Java 8和之后构建的。这些阶级取代了麻烦的旧阶级。 遗产 日期时间类,如 java.util.Date , Calendar ,& SimpleDateFormat .

    这个 Joda-Time 项目,现在在 maintenance mode ,建议迁移到 java.time时间 课程。

    要了解更多信息,请参阅 Oracle Tutorial . 以及搜索堆栈溢出以获得许多示例和解释。规格为 JSR 310 .

    在哪里获取java.time类?

    这个 ThreeTen-Extra Project使用其他类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter more .