Java 如何表示特定的日历周期(月、周等)

Java 如何表示特定的日历周期(月、周等),java,jodatime,Java,Jodatime,据我所知,Joda time的主要概念是: 具有毫秒粒度的即时时间(由DateTime表示) Interval表示两个实例的跨度 持续时间实际上只是一个长的毫秒数 一个周期,它类似于一个未锚定的时间长度,它不是以精确的毫秒数定义的,而是根据诸如“月”、“日”等概念的常见民间用法定义的 那么我应该如何表示,例如“2014年2月”。有那种类型的吗?我知道我可以将其表示为一个瞬间的元组(在该月的开始或结束时)和一个月的周期。但这意味着我在Joda的基础上定义了自己的类型,并且我必须决定一个约定,即

据我所知,Joda time的主要概念是:

  • 具有毫秒粒度的即时时间(由
    DateTime
    表示)
  • Interval
    表示两个实例的跨度
  • 持续时间实际上只是一个
    长的
    毫秒数
  • 一个
    周期
    ,它类似于一个未锚定的时间长度,它不是以精确的毫秒数定义的,而是根据诸如“月”、“日”等概念的常见民间用法定义的
那么我应该如何表示,例如“2014年2月”。有那种类型的吗?我知道我可以将其表示为一个瞬间的元组(在该月的开始或结束时)和一个月的
周期。但这意味着我在
Joda
的基础上定义了自己的类型,并且我必须决定一个约定,即该瞬间是在我希望定义的时间段的开始还是结束(因为这两个选项显然都是可行的)

我拥有的用例是,我需要生成报告,如果用户:

  • 只是碰巧选择了两个恰好在2014年2月初和2月底的实例
  • 被选中为2014年2月编制月度报告
那么,有没有一种单一的类型?如果失败了,那么什么是最好的方法来表示它。

中的类提供了这个功能,持续了几个月

因此,要获取1970年1月和历元第一个月开始和结束实例的历元值后的秒数:

    YearMonth yearMonth = new YearMonth (1970, 1);
    Interval interval = yearMonth.toInterval(DateTimeZone.UTC);
    int startSSE = (int) TimeUnit.MILLISECONDS.toSeconds(interval.getStartMillis());
    int   endSSE = (int) TimeUnit.MILLISECONDS.toSeconds(interval.getEndMillis());
    System.out.printf("%d -> %d (%4.6f days)\n", startSSE, endSSE, ((float)(endSSE-startSSE))/(24*60*60));

目前我在Joda Time YearMonth类中的运气不好,所以这里有一个使用DateTimeFormatter的替代示例

public static DateTimeFormatter DATEFORMATTER = new DateTimeFormatterBuilder()
    .appendPattern("MMM, YYYY").toFormatter();
我为您添加了println()的示例代码

/**
     * calculates the number of months between the upper and lower bounds 
     * example: int m = numberOfMonths("January, 2009", "May, 2000");   
     *          >m=104
     * Uses Joda
     * Months are full month names
     * @return
     */
    public int numberOfMonths(String upperMMMMcommaYYYY, String lowerMMMMcommaYYYY){
        DateTime upper = DATEFORMATTER.parseDateTime(upperMMMMcommaYYYY);
        DateTime lower = DATEFORMATTER.parseDateTime(lowerMMMMcommaYYYY);
        Months m = Months.monthsBetween(lower, upper);
        System.out.println(upperMMMMcommaYYYY.concat("printed from DateTime looks like ".concat(upper.toString(DATEFORMATTER))));
        return m.getMonths;

    }
使用DateTimeFormatter+DateTime的println结果->2009年1月看起来像2009年1月

tl;博士 使用现代java.time类取代Joda time项目和最初与java最早版本捆绑在一起的麻烦的旧遗留日期时间类

YearMonth.of( 2014 , Month.FEBRUARY )
java.time 现代方法使用java.time(JSR310)类,这些类是Joda time项目的正式继承者。这两个项目都由同一个人斯蒂芬·科尔伯恩领导

YearMonth
那么我应该如何表示,例如“2014年2月”

使用专门为此设计的

您可以使用1月至12月的sane编号1-12,按编号指定年和月(与传统类不同)

或者使用方便的枚举

ISO 8601 要将年-月表示为文本,请使用标准格式:YYYY-MM

String output = ym.toString() ;
2014-02

还有这样的弦

YearMonth ym = YearMonth.parse( "2014-02" ) ; 
据我所知,没有数据库具有年-月数据类型。因此,我建议在表中使用一个文本列,其中包含ISO 8601格式的字符串。请注意,此ISO 8601格式的字母排序碰巧也是按时间顺序排序的

Period
一个月的时间

期间
未附加到时间线。类似于
Period.ofMonths(1)
的内容表示与任何日期或日历无关的通用月份

相反,
YearMonth
表示一个特定的月份。将
YearMonth
附加到时间线

片刻 如果您需要特定的日期和时间,例如查询数据库,则需要确定日期。该类表示一个仅限日期的值,不包含一天中的时间和时区

LocalDate ldStart = ym.atDay( 1 ) ;                 // First of the month.
LocalDate ldStop = ym.plusMonths( 1 ).atDay( 1 ) ;  // First day of the following month.
使用时间值确定日期需要时区

LocalDate ldStart = ym.atDay( 1 ) ;                 // First of the month.
LocalDate ldStop = ym.plusMonths( 1 ).atDay( 1 ) ;  // First day of the following month.
时区对于确定有时间的日期至关重要。在任何一个特定的时刻,世界各地的日期都因地区而异。例如,中午夜后几分钟是新的一天,而中仍然是“昨天”

如果未指定时区,JVM将隐式应用其当前默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将所需/预期时区明确指定为参数

大陆/地区
的格式指定,例如,或
太平洋/奥克兰
。切勿使用3-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

使用该区域让java.time确定一天中的第一个时刻。不要假设一天从00:00:00开始。某些区域中的某些日期在一天中的其他时间开始,例如01:00:00

ZonedDateTime zdtStart = ldStart.atZone( z ) ;  // First moment of the day starting in the wall-clock time used by the people of a particular region (a time zone).
ZonedDateTime zdtStop = ldStop.atZone( z ) ;
然后,您可以提取UTC值,数据库通常使用这些值将值存储在SQL standard
TIME Stamp WITH TIME ZONE
的列中

Instant instantStart = zdtStart.toInstant() ;
Instant instantStop = zdtStop.toInstant() ;
JDBC 从JDBC4.2及更高版本开始,您可以与数据库交换java.time对象

myPreparedStatement.setObject( … , instantStart ) ;
myPreparedStatement.setObject( … , instantStop ) ;
检索

Instant instant = myResultSet.getObject( … , Instant.class ) ;

关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

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

从哪里获得java.time类

  • 然后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(我在实现报表时也有同样的要求。我最终实现了自己的类,包含startdate、enddate、periodName、periodType(周、月、季度……)
      myPreparedStatement.setObject( … , instantStart ) ;
      myPreparedStatement.setObject( … , instantStop ) ;
      
      Instant instant = myResultSet.getObject( … , Instant.class ) ;