【问题标题】:How to check which week and month days given interval consist of?如何检查给定间隔包含哪些星期和月份?
【发布时间】:2018-03-01 05:32:45
【问题描述】:

假设我有两个 LocalDate 对象,fromDate 和 toDate。 我需要知道间隔内有哪些工作日 - 星期一、星期二等。 而且,我还想知道哪些 daysOfMonth - 1 日、2 日,或者例如仅 20 日 - 从 20 日到 23 日。 Joda 时间库中是否有任何有用的工具/方法可以帮助我?我不是在询问特定的算法,我可以自己编写它,但我不确定 Joda 的功能 - 也许它已经有了我可以重复使用的东西。

【问题讨论】:

标签: java calendar jodatime


【解决方案1】:

这与我想的差不多:

Days between

或者可能是这样的(假设只有两个不同的月份):

public Boolean dayOfMonthExistInPeriod(final int dayOfMonth, final LocalDate from, final LocalDate until){
        final DateMidnight tested = new DateMidnight(from.getYear(), from.getMonthOfYear(), dayOfMonth);
        final DateMidnight tested2 = new DateMidnight(until.getYear(), until.getMonthOfYear(), dayOfMonth);
        final Interval interval = new Interval(from.toDateMidnight(), until.toDateMidnight());
        return interval.contains(tested) && interval.contains(tested2);
    }

【讨论】:

  • 但它只允许我计算两个日期之间的天数,这对我来说并不重要。当然,如果这个数量 > 7,那么我可以确定这个间隔包括从周一到周日的所有工作日。但是,如果间隔少于 7 天呢?我不知道它是否包括星期一,除非我每天都会重复这看起来像是一场噩梦......如果我开始考虑如何决定这个间隔是否包括一个月的第 28 天,情况会变得更糟......
  • 这几乎不是一场噩梦——你不需要遍历每一个来确定是否包含了一周中的某一天;还有 dayOfMonth() 和 dayOfWeek() 属性。
  • Class Days 不包含这些属性,它是 LocalDate 属性.. 所以您建议在间隔中每天迭代以检查 dayOfMonth() 和 dayOfWeek() ?
  • 不,我不建议这样做。我不确定您的确切要求,但它的计算非常简单,可以确定是否存在给定日期或一周中的给定日期 - 无需在此期间的每一天进行迭代。
  • 我敢肯定,如果它很简单,您不会介意编写简短的简单代码 sn-p 来计算间隔 11.04.2012-02.05.2012 是否包含每月的第 31 天
【解决方案2】:
public static boolean isDayBetween(int dtc, DateTime from, DateTime to)
   {
      final int dayOfWeekFrom = from.dayOfWeek().get();
      final int daysBetween = Days.daysBetween(from, to).getDays();
      if (dtc >= dayOfWeekFrom && dtc <= (dayOfWeekFrom + daysBetween))
         return true;
      return false;
   }  

使用方法

DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd");
final DateTime from = dtf.parseDateTime("2000-07-08");
final DateTime to = dtf.parseDateTime("2000-07-13");
boolean res = isDayBetween(from, to, DateTimeConstants.THURSDAY)

【讨论】:

    【解决方案3】:

    tl;博士

    java.time.LocalDate.of( 2018 , Month.JANUARY , 23 )
        .plusDays( 1 )
        .getDayOfWeek()  // Returns a `DayOfWeek` enum object such as `DayOfWeek.MONDAY`.
    

    ……和……

    java.time.LocalDate.of( 2018 , Month.JANUARY , 23 )
        .plusDays( 1 )
        .getDayOfMonth()  // Returns an integer number, 1-31.
    

    java.time

    现代方法使用 java.time 类取代了最早的 Java 和 Joda-Time 项目中遗留的日期时间类。 Joda-Timejava.time/JSR 310 都是由同一个人 Stephen Colebourne 领导的,因此它们的概念非常一致。

    LocalDate

    LocalDate 类表示没有时间和时区的仅日期值。

    LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
    LocalDate stop = LocalDate.of( 2018 , Month.FEBRUARY , 4 ) ;
    

    使用ChronoUnit 枚举可以轻松计算经过的天数。

    long days = ChronoUnit.DAYS.between( start , stop ) ;
    

    该计算是使用半开方法进行的,其中开头是包含,而结尾是排除。这种方法通常是定义时间跨度的明智方法。

    我需要知道间隔内有哪些工作日 - 星期一、星期二等。

    有一个类:DayOfWeekenum 定义七个对象,一个用于一周中的每一天。 EnumSet 类是 Set 的高度优化实现,用于收集 DayOfWeek 对象。 Set 吸收/忽略重复项,因此我们最终会得到一个不同的集合。

    final int countDaysInWeek = DayOfWeek.values().length ;  // Seven days in a week.
    Set< DayOfWeek > dows = EnumSet.noneOf( DayOfWeek.class ) ;
    LocalDate ld = start ;
    while ( ld.isBefore( stop ) ) {
        dows.add( ld.getDayOfWeek() ) ;  // Add each date’s day-of-week to our collection.
        if ( dows.size() == countDaysInWeek ) { break ; }  // Bail out of this loop after collecting all the days of the week.
        ld = ld.plusDays( 1 ) ;  // Increment to the next day, to setup the next loop. The java.time classes use immutable objects, so we are generating a fresh object here rather than modifying the original.
    }
    

    而且,我还想知道哪些 daysOfMonth - 1 日、2 日,或者例如仅 20 日 - 从 20 日到 23 日。

    可以收集月份中的日期,但我怀疑这就是您想要的。

    List< Integer > dayOfMonthNumbers = new ArrayList<>() ;
    LocalDate ld = start ;
    while ( ld.isBefore( stop ) ) {
        dayOfMonthNumbers.add( ld.getDayOfMonth() ) ;
        ld = ld.plusDays( 1 ) ;  // Increment to next date.
    }
    

    如果您转入另一个月份,您最终会得到如下列表:29 , 30 , 1 , 2。我怀疑您会发现使用 LocalDate 对象的集合而不是仅仅使用月份中的日期更有用。

    List< LocalDate > dates = new ArrayList<>() ;
    LocalDate ld = start ;
    while ( ld.isBefore( stop ) ) {
        dates.add( ld ) ;
        ld = ld.plusDays( 1 ) ;  // Increment to next date.
    }
    

    从那里您可以使用DateTimeFormatter 生成字符串来表示这些日期值。搜索 Stack Overflow 以获取更多信息,因为这已被多次介绍。

    ThreeTen-Extra & LocalDateRange

    提示:如果您将 ThreeTen-Extra 库添加到您的项目中,您可以使用 LocalDateRange 类来表示您的时间跨度。

    LocalDateRange range = LocalDateRange.of( start , stop ) ;
    

    关于java.time

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

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-16
      • 1970-01-01
      • 2021-12-16
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      相关资源
      最近更新 更多