Joda时间 plusDays 得到错误的日期

huangapple go评论70阅读模式
英文:

Joda time plusDays getting wrong date

问题

我正在使用这段代码:

 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
对于某些日期,它运行良好,但对于其他日期,结果会减少一天,我猜问题可能在于月份中的天数,但是 plusDays() 方法不会考虑这一点吗?

英文:

I am using this code:

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

And the result is Fri Dec 18 23:00:00 GMT+02:00 2020 instead of Dec 19.
With some dates it work well, with other the result date-1, I guess the problem is with number of days in month, but does plusDays() not consider it?

答案1

得分: 3

你可以使用 java.time,并且它在较低的Android API中得到支持,因为现在Android中有API desugaring

有一个带有时区信息的类 (java.time.ZonedDateTime) 和一个带有偏移信息的类 (java.time.OffsetDateTime),但是你的示例 String 只包含了相对于 GMT / UTC 的偏移量。这就是为什么我会使用一个 OffsetDateTime,它解析了确切的时间点,然后再添加一天。

下面是一个简单的示例,定义了一个格式化器来解析给定的 String,并将其用于输出:

public static void main(String[] args) {
	// 示例 String
	String date = "Fri Dec 18 23:00:00 GMT+02:00 2020";
	// 创建一个能够解析和输出该 String 的格式化器
	DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss OOOO uuuu",
														Locale.ENGLISH);
	// 使用上面定义的格式化器解析该 String
	OffsetDateTime odt = OffsetDateTime.parse(date, dtf);
	System.out.println("解析得到的 OffsetDateTime 为\t" + odt.format(dtf));
	
	// 在日期部分加上一天
	OffsetDateTime dayLater = odt.plusDays(1);
	System.out.println("添加一天后的结果为\t\t" + dayLater.format(dtf));
}

这将输出

解析得到的 OffsetDateTime 为	Fri Dec 18 23:00:00 GMT+02:00 2020
添加一天后的结果为		Sat Dec 19 23:00:00 GMT+02:00 2020

如果你只想输出日期(不包含时间部分或偏移量),这些类中还有另一个有用的功能,即轻松提取日期或时间部分。例如,你可以对 OffsetDateTime 做以下操作:

// 提取仅包含日期、月份和年份信息的部分
LocalDate dateOnly = odt.toLocalDate();
// 打印默认格式(ISO 标准)
System.out.println(dateOnly);
// 或者定义并使用完全自定义的格式
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); 简单地添加一天。

英文:

You could use java.time and it is supported in lower Android APIs, because there's API desugaring in Android now.

There's a zone-aware class (java.time.ZonedDateTime) and an offset-aware one (java.time.OffsetDateTime), but your example String just contains an offset from GMT / UTC. That's why I would use an OffsetDateTime that parses the exact moment in time and then adds a day.

Here's a simple example that defines a formatter which parses the given String and uses it for the output:

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));
}

This outputs

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

If you are interested in outputting dates only (no time part or offset), there's another handy thing in those classes, that is easy extraction of date- or time-part. You can do the following with an OffsetDateTime, for example:

// 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)
					)
);

That would output

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

In case you are dealing with a DatePicker datePicker, you can receive selected values by getYear(), getMonth() and getDayOfMonth(), then create a

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

and then simply add a day by localDate.plusDays(1);

答案2

得分: 2

以下是翻译好的内容:

对于某些日期,它运行良好,对于其他日期,结果为日期-1,我猜问题在于每个月的天数,但是plusDays()不考虑这一点吗?
它确实考虑了。你提到的两个日期时间字符串的问题在于它们属于不同的区偏移(第一个是UTC+3,第二个是UTC+2)。以下是如何在相同的区偏移下进行操作的示例。

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);
        // 使用UTC+2的区偏移
        System.out.println(dateTime.withZone(DateTimeZone.forOffsetHours(2)));

        // 添加103天
        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

我建议你使用现代java.time日期时间API,以及相应的格式化API(包名:java.time.format)。你可以从**教程:日期时间**中了解有关现代日期时间API的更多信息。如果你的Android API级别仍不符合Java 8,可以查看https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project和通过解糖获得的Java 8+ API支持

下表显示了现代日期时间类的概览

Joda时间 plusDays 得到错误的日期

使用现代日期时间API:

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

public class Main {
    public static void main(String[] args) {
        // 定义你的日期时间字符串的格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O u");

        // 将给定的日期时间字符串解析为OffsetDateTime对象
        OffsetDateTime dateTime = OffsetDateTime.parse("Thu Aug 06 00:00:00 GMT+03:00 2020", formatter);
        System.out.println(dateTime);

        // 在OffsetDateTime对象上添加103天
        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) {
        // 定义你的日期时间字符串的格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy");

        // 如果你不需要区域ID或区偏移信息,你可以使用LocalDateTime
        LocalDateTime dateTime = LocalDateTime.parse("Thu Aug 06 00:00:00 GMT+03:00 2020", formatter);
        System.out.println(dateTime);

        // 你可以通过应用区偏移来将LocalDateTime对象转换为OffsetDateTime,例如下面的代码行将UTC+03:00小时应用于LocalDateTime
        OffsetDateTime odt = dateTime.atOffset(ZoneOffset.ofHours(3));
        System.out.println(odt);

        // 在LocalDateTime对象上添加103天
        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
英文:

> With some dates it work well, with other the result date-1, I guess
> the problem is with number of days in month, but does plusDays() not
> consider it?

It does consider it. The problem with the two date-time strings you have mentioned is that they belong to different Zone-Offset (the first one is with UTC+3 and the second one with UTC+2). Given below is how to do it with the same 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)));
	}
}

Output:

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

I recommend you use the modern java.time date-time API and the corresponding formatting API (package, java.time.format). Learn more about the modern date-time API from Trail: Date Time. If your Android API level is still not compliant with Java8, check https://stackoverflow.com/questions/38922754/how-to-use-threetenabp-in-android-project and Java 8+ APIs available through desugaring.

The following table shows an overview of modern date-time classes:
Joda时间 plusDays 得到错误的日期

With modern date-time 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);
	}
}

Output:

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

Alternatively,

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);
	}
}

Output:

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

huangapple
  • 本文由 发表于 2020年9月7日 16:47:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/63774253.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定