【问题标题】:Joda time plusDays getting wrong dateJoda time plusDays 日期错误
【发布时间】:2020-12-25 16:18:18
【问题描述】:

我正在使用此代码:

 DateTime(date)//Thu Aug 06 00:00:00 GMT+03:00 2020
                .plusDays(days) // 103
                .toDate()

结果是Fri Dec 18 23:00:00 GMT+02:00 2020 而不是Dec 19。 对于某些日期,它运行良好,对于其他结果 date-1,我想问题出在一个月的天数上,但 plusDays() 不考虑吗?

【问题讨论】:

  • 您必须使用 JodaTime 还是可以使用 java-time (Java 8+)?
  • 如果Android api 21+支持java-time那么我可以使用
  • 这可能是由于夏令时。时区偏移在 10 月 25 日附近从 +3 变为 +2。

标签: java android datetime jodatime android-jodatime


【解决方案1】:

我猜有些日期效果很好,而其他结果日期为 1 问题是一个月的天数,但 plusDays() 不是 考虑一下?

它确实考虑过。您提到的两个日期时间字符串的问题是它们属于不同的区域偏移(第一个是 UTC+3,第二个是 UTC+2)。下面给出了如何使用相同的 Zone-Offset。

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss zZ yyyy");
        DateTime dateTime = DateTime.parse("Thu Aug 06 00:00:00 GMT+03:00 2020", formatter);
        System.out.println(dateTime);
        // With Zone-Offset of UTC+2
        System.out.println(dateTime.withZone(DateTimeZone.forOffsetHours(2)));

        // Add 103 days
        DateTime dateTimeAfter103Days = dateTime.plusDays(103);
        System.out.println(dateTimeAfter103Days);
        System.out.println(dateTime.withZone(DateTimeZone.forOffsetHours(2)));
    }
}

输出:

2020-08-05T21:00:00.000Z
2020-08-05T23:00:00.000+02:00
2020-11-16T21:00:00.000Z
2020-08-05T23:00:00.000+02:00

我建议您使用modern java.time 日期时间API 和相应的格式化API(包,java.time.format)。从 Trail: Date Time 了解有关现代日期时间 API 的更多信息。如果您的 Android API 级别仍然不符合 Java8,请检查 How to use ThreeTenABP in Android ProjectJava 8+ APIs available through desugaring

下表显示了overview of modern date-time classes

使用现代日期时间 API:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // Define formatter for your date-time string
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O u");

        // Parse the given date0-time string into OffsetDateTime object
        OffsetDateTime dateTime = OffsetDateTime.parse("Thu Aug 06 00:00:00 GMT+03:00 2020", formatter);
        System.out.println(dateTime);

        // Add 103 days to the OffsetDateTime object
        OffsetDateTime dateTimeAfter103Days = dateTime.plusDays(103);
        System.out.println(dateTimeAfter103Days);
    }
}

输出:

2020-08-06T00:00+03:00
2020-11-17T00:00+03:00

或者,

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // Define formatter for your date-time string
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy");

        // If you do not need Zone Id or Zone Offset information, you can go for
        // LocalDateTime
        LocalDateTime dateTime = LocalDateTime.parse("Thu Aug 06 00:00:00 GMT+03:00 2020", formatter);
        System.out.println(dateTime);

        // You can convert LocalDateTime object into an OffsetDateTime by applying the
        // Zone-Offset e.g. the following line applies UTC+03:00 hours to LocalDateTime
        OffsetDateTime odt = dateTime.atOffset(ZoneOffset.ofHours(3));
        System.out.println(odt);

        // Add 103 days to the LocalDateTime object
        LocalDateTime dateTimeAfter103Days = dateTime.plusDays(103);
        System.out.println(dateTimeAfter103Days);

        odt = dateTimeAfter103Days.atOffset(ZoneOffset.ofHours(3));
        System.out.println(odt);
    }
}

输出:

2020-08-06T00:00
2020-08-06T00:00+03:00
2020-11-17T00:00
2020-11-17T00:00+03:00

【讨论】:

    【解决方案2】:

    您可以使用java.time,它在较低的Android API 中受支持,因为现在有API desugaring in Android

    有一个区域感知类 (java.time.ZonedDateTime) 和一个偏移感知类 (java.time.OffsetDateTime),但您的示例 String 仅包含与 GMT / UTC 的偏移量。这就是为什么我会使用 OffsetDateTime 来解析确切的时间然后添加一天。

    这是一个简单的示例,它定义了一个格式化程序,它解析给定的String 并将其用于输出:

    public static void main(String[] args) {
        // example String
        String date = "Fri Dec 18 23:00:00 GMT+02:00 2020";
        // create a formatter that is able to parse and output the String
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss OOOO uuuu",
                                                            Locale.ENGLISH);
        // parse the String using the formatter defined above
        OffsetDateTime odt = OffsetDateTime.parse(date, dtf);
        System.out.println("OffsetDateTime parsed is\t" + odt.format(dtf));
        
        // add a day to the date part
        OffsetDateTime dayLater = odt.plusDays(1);
        System.out.println("Adding a day results in\t\t" + dayLater.format(dtf));
    }
    

    这个输出

    OffsetDateTime parsed is    Fri Dec 18 23:00:00 GMT+02:00 2020
    Adding a day results in     Sat Dec 19 23:00:00 GMT+02:00 2020
    

    如果您只对输出日期感兴趣(没有时间部分或偏移量),那么这些类中还有另一个方便的功能,即轻松提取日期或时间部分。您可以使用OffsetDateTime 执行以下操作,例如:

    // extract the part that only holds information about day of month, month of year and year
    LocalDate dateOnly = odt.toLocalDate();
    // print the default format (ISO standard)
    System.out.println(dateOnly);
    // or define and use a totally custom format
    System.out.println(dateOnly.format(
                            DateTimeFormatter.ofPattern("EEEE, 'the' dd. 'of' MMMM uuuu",
                                                        Locale.ENGLISH)
                        )
    );
    

    那会输出

    2020-12-18
    Friday, the 18. of December 2020
    

    如果您正在处理DatePicker datePicker,您可以通过getYear()getMonth()getDayOfMonth() 接收选定的值,然后创建一个

    LocalDate localDate = LocalDate.of(datePicker.getYear(),
                                       datePicker.getMonth(), 
                                       datePicker.getDayOfMonth());
    

    然后通过localDate.plusDays(1);简单地添加一天

    【讨论】:

    • but your example String just contains an offset from GMT / UTC 实际上是来自 DatePicker 的 java Date 对象
    • @PavelPoley 您可以从DatePicker 获取年、月和日,并从中创建LocalDate。我不会再使用java.util.Date,因为你的例子中的问题。查看我编辑的答案...
    • 为什么要使用localDate.plusDays(1)
    • @PavelPoley 这只是一个例子,你可以在那里输入任何int。如果你有int days = 103;,那就做localDate.plusDays(days);,没问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 2014-03-24
    • 1970-01-01
    • 2019-03-21
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多