如何表示特定日历期(月,周等)

时间:2014-02-21 17:56:55

标签: java jodatime

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

  • 以毫秒粒度(由DateTime表示)
  • 的即时时间
  • Interval代表两个实例的范围
  • 持续时间,实际上只有long毫秒数
  • 一个Period,就像一个未锚定的时间长度,不是根据精确的毫秒数定义的,而是根据“月”,“日”等概念的常见民用用途。 LI>

我应该如何表示,例如“2014年2月”。有那种类型吗?我知道我可以把它表示为瞬间(在那个月的开头或结尾)和一个月Period的元组。但这意味着我在Joda之上定义了自己的类型,我必须决定关于瞬间是否应该在我希望定义的时期的开始或结束的约定(因为两个选项都清楚可行的)。

我正在使用的用例是我需要生成报告,如果用户:

它确实会对报告标题/说明产生影响
  • 只是恰好在2014年2月开始和结束时选择了两个实例
  • 选择制作2014年2月的月度报告。

那么,有一种类型吗?并且,失败,那是什么,最好的方法来代表那个。

3 个答案:

答案 0 :(得分:2)

YearMonth中的Joda-Time类提供此功能,持续数月。

因此,要获得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));

答案 1 :(得分:1)

TL;博士

使用现代的 java.time 类来取代Joda-Time项目和最初与最早版本的Java捆绑在一起的麻烦的旧旧日期时间类。

YearMonth.of( 2014 , Month.FEBRUARY )

java.time

现代方法使用 java.time (JSR 310)类,它们是Joda-Time项目的官方继承者。这两个项目都由同一个人Stephen Colebourne领导。

YearMonth

  

我应该如何表示,例如“2014年2月”。

使用专为此目的而构建的YearMonth

您可以按编号指定年份和月份,使用1到12月的理智编号1-12(与旧版课程不同)。

YearMonth ym = YearMonth.of( 2014 , 2 ) ;  // 2014 February.

或者使用方便的Month枚举。

YearMonth ym = YearMonth.of( 2014 , Month.FEBRUARY ) ;

ISO 8601

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

String output = ym.toString() ;
  

2014-02

parse这样的字符串。

YearMonth ym = YearMonth.parse( "2014-02" ) ; 

我所知道的数据库没有年月数据类型。因此,我建议在表中使用包含ISO 8601格式字符串的文本列。请注意,此ISO 8601格式的字母排序也按时间顺序排序。

Period

  

一个月的时间。

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

相比之下,YearMonth表示一个特定的月。 YearMonth 附加到时间轴。

如果您需要特定的日期时间,例如查询数据库,则需要确定日期。 LocalDate类表示没有时间且没有时区的仅限日期的值。

LocalDate ldStart = ym.atDay( 1 ) ;                 // First of the month.
LocalDate ldStop = ym.plusMonths( 1 ).atDay( 1 ) ;  // First day of the following month.

确定带时间的日期值需要一个时区。

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

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

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

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

使用该区域让 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标准TIMESTAMP WITH TIME ZONE的列中。

Instant instantStart = zdtStart.toInstant() ;
Instant instantStop = zdtStop.toInstant() ;

JDBC

从JDBC 4.2及更高版本开始,您可以将 java.time 对象与数据库进行交换。

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

检索。

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

关于 java.time

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

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

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

答案 2 :(得分:0)

目前我对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;

    }

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