使用Joda-Time API

时间:2017-06-25 07:48:16

标签: java datetime jodatime datetime-format datetime-parsing

我想以下列格式生成一系列时间(yyyy-mm-dd hh:mm:ss),时间间隔为15分钟。我将给出开始日期和结束日期。

使用以下代码测试相同的代码。

public static void main(String[] args) throws ParseException {
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-mm-dd HH:mm:ss");
        DateTime dt1 = formatter.parseDateTime("2017-06-21 00:00:00");
        DateTime dt2 = formatter.parseDateTime("2017-06-23 00:00:00");

        DateTime dateTime1 = new DateTime(dt1);

        DateTime dateTime2 = new DateTime(dt2);
        List<Date> allDates = new ArrayList();

        while( dateTime1.isBefore(dateTime2) ){
           allDates.add( dateTime1.toDate() );
           dateTime1 = dateTime1.plusMinutes(15);

           System.out.println(dateTime1);
        }

它生成如下输出:

  

2017-01-21T00:15:00.000 + 05:30

预期输出为2017-06-21 00:00:00,它没有找到我想要的正确日期。

2 个答案:

答案 0 :(得分:1)

TL;博士

使用java.time类,它取代了Joda-Time项目。将输入转换为标准格式以便于解析。

LocalDateTime.parse( 
    "2017-06-23 00:00:00".replace( " " , "T" ) 
).plus( Duration.ofMinutes( 15 ) ) 

详细

如JB Nizet所述,您在格式化模式中使用的代码不正确。显然你猜测代码而不是阅读文档 - 这是一种不明智的做法。这些代码已经在Stack Overflow上被覆盖了数百次,所以显然你在这里发帖而不必费心去第一次搜索。

Joda-Time vs java.time

您正在使用Joda-Time库。该项目现在处于维护模式,团队建议迁移到java.time类。

ISO 8601标准

您的输入字符串几乎符合ISO 8601标准。要完全符合要求,请使用T替换中间的SPACE。在解析/生成字符串时,java.time类默认使用ISO 8601格式。所以不需要定义任何格式化模式。

关于LocalDateTime

的警告

您的输入缺少任何时区或offset-from-UTC的指示。所以我们将解析为LocalDateTime。请注意LocalDateTime不是真正的时刻,而不是时间轴上的实际点。如果没有时区或偏移的上下文,LocalDateTime是不现实的。

解决方案

LocalDateTime start = LocalDateTime.parse( "2017-06-21 00:00:00".replace( " " , "T" ) ) ;
LocalDateTime stop = LocalDateTime.parse( "2017-06-23 00:00:00".replace( " " , "T" ) ) ;

对于防御性编程,请确认您的开始是在停止之前。类似于stop.isAfter( start )

在每个循环中,添加指定的持续时间为15分钟。

Duration d = Duration.ofMinutes( 15 ) ;
LocalDateTime ldt = start ;
List< LocalDateTime > ldts = new ArrayList<>() ;

while( ! ldt.isAfter( stop ) ) {  // "Not after" is a shorter way of saying "is earlier than or is equal to".
    ldts.add( ldt ) ;
    // Set up the next loop.
    ldt = ldt.plus( d ) ;
}

关于java.time

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

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

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

从哪里获取java.time类?

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

答案 1 :(得分:0)

首先,read the javadoc。小写mm模式对应分钟。要获得,您需要使用大写MM。所以,你的格式化程序将是这样的:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

你不需要这样做:

DateTime dateTime1 = new DateTime(dt1);

这是多余的,因为您正在创建2个相同的对象。只需使用parseDateTime方法返回的日期即可。或者只是做:

DateTime dateTime1 = dt1;

您已经创建了DateTimeFormatter,因此只需使用它来格式化输出。而不是:

System.out.println(dateTime1);

这样做:

System.out.println(formatter.print(dateTime1));

print方法将以您希望的格式返回日期。

我不确定您是否要打印第一个日期(2017-06-21 00:00:00)。如果您需要,只需更改plusMinutesSystem.out.println行的顺序。

新Java日期/时间API

Joda-Time处于维护模式,正在被新API取代,所以我不建议用它来启动新项目。即使在joda's website它也说:&#34;请注意,Joda-Time被认为是一个很大程度上“完成”的项目。没有计划重大改进。如果使用Java SE 8,请迁移到java.time(JSR-310)。&#34;

因此,如果您可以迁移Joda-Time代码或启动新项目,请考虑使用新API。如果您使用 Java 8 ,则可以使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您正在使用 Java&lt; = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为java.time而在ThreeTen Backport(或Android的ThreeTenABP中)为org.threeten.bp),但类和方法名称是相同的。

逻辑非常相似。唯一的区别是我使用了LocalDateTime类,并将其转换为java.util.Date我需要知道它在什么时区。我使用了系统的默认时区,这可能是您想要的(因为您的原始代码也使用默认时区):

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime1 = LocalDateTime.parse("2017-06-21 00:00:00", formatter);
LocalDateTime dateTime2 = LocalDateTime.parse("2017-06-23 00:00:00", formatter);

List<Date> allDates = new ArrayList();

while (dateTime1.isBefore(dateTime2)) {
    // get the date in the system default timezone and convert to java.util.Date
    allDates.add(Date.from(dateTime1.atZone(ZoneId.systemDefault()).toInstant()));
    dateTime1 = dateTime1.plusMinutes(15);

    System.out.println(formatter.format(dateTime1));
}

在Java 8中,Date.from方法可用。在ThreeTen Backport(Java 7和Android)中,您可以改为使用org.threeten.bp.DateTimeUtils类:

allDates.add(DateTimeUtils.toDate(dateTime1.atZone(ZoneId.systemDefault()).toInstant()));