【问题标题】:Get the First day and the last day of month from an Instant从 Instant 获取每月的第一天和最后一天
【发布时间】:2019-03-04 19:56:24
【问题描述】:

我有一个在参数getIssuesBillable(Instant start, Instant end, ....) 中使用 2 个 Instants 的方法,我的问题是如何使用 Java 8 Instant 获得一个月的第一天和一个月的最后一天? 我已经尝试过使用 withDayOfMonth()lengthOfMonth()

LocalDate initial = LocalDate.now();
LocalDate start = initial.withDayOfMonth(firstDayOfMonth());
LocalDate end = initial.withDayOfMonth(lastDayOfMonth());

但在这种情况下,我需要转换并在这种情况下做出一些解决方法,如果有人知道更好的方法,我真的很感激任何回应。

【问题讨论】:

    标签: java validation date


    【解决方案1】:

    tl;博士

    使用现代 java.time 类。

    这是一个简短的无意义示例,它以 Instant(UTC 时刻)开始,分配时区以通过特定地区(时区)的人们使用的挂钟时间查看该时刻,提取在该时区感知的年份和月份,并确定该月的第一天和最后一天,渲染LocalDate 对象。

    YearMonth                                 // Represent a year-and-month, the entire month as a whole.
    .from(                                    // Determine the year-and-month of some other date-time object.
        Instant                               // Represent a moment in UTC.
        .now()                                // Capture the current moment in UTC.
        .atZone(                              // Adjust from UTC to a particular time zone.
            ZoneId.of( "Pacific/Auckland" ) 
        )                                     // Returns a `ZonedDateTime` object.
    )                                         // Returns a `YearMonth` object.
    .atDay( 1 )                               // Returns a `LocalDate` object.
    

    …或

    …
    .atEndOfMonth()                           // Returns a `LocalDate` object.
    

    顺便说一句,该特定代码的实际版本是:YearMonth.now( ZoneId.of( "Pacific/Auckland" ) ).atDay( 1 )

    时刻与仅日期

    InstantUTC 中的一个时刻,是一个日期时间,offset-from-UTC 为零。

    LocalDate 是一个仅限日期的值,没有时间和time zone

    您需要指定您想要感知日期的时区,即特定地区人们使用的挂钟时间。

    时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

    如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将您的 desired/expected time zone 明确指定为参数。

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

    ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
    ZonedDateTime zdt = instant.atZone( z ) ;
    

    仅提取日期。

    LocalDate ld = zdt.toLocalDate() ;
    

    从那里,继续您的其他代码。

    或者使用YearMonth 类来处理整个月份。

    YearMonth ym = YearMonth.from( zdt ) ;
    LocalDate first = ym.atDay( 1 ) ;
    LocalDate last = ym.atEndOfMonth() ;
    

    提示:ThreeTen-Extra 库中的 LocalDateRangeInterval 类可能会对您有所帮助。

    提示:了解定义时间跨度的半开放方法,其中开始是包含,而结束是不包含。因此,一个月从第一天开始,一直持续到但不包括月的第一天。


    关于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

    【讨论】:

      【解决方案2】:

      每月的第一天,取决于时区:

      YearMonth.from(Instant.now().atZone(ZoneId.of("UTC"))).atDay(1);
      

      一个月的最后一天,取决于时区:

      YearMonth.from(Instant.now().atZone(ZoneId.of("UTC"))).atEndOfMonth();
      

      【讨论】:

      • 它已经在另一个答案中了。很高兴也有简短的版本。
      • ty 用于短版分享
      猜你喜欢
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 2015-04-03
      • 2013-11-25
      相关资源
      最近更新 更多