如何从 GregorianCalendar 修复 gc.setTime()

How to make gc.setTime() from GregorianCalendar fixed

这是我的代码的一部分:

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(dateFormat.parse(jahr+"-"+monat+"-"+tag));

现在我想打印出德国的一些感人的复活节假期。

gc.add(Calendar.DAY_OF_MONTH, -2);
System.out.println("Karfreitag;"+dateFormat.format(gc.getTime()));
gc.add(Calendar.DAY_OF_MONTH, +3);
System.out.println("Ostermontag;"+dateFormat.format(gc.getTime()));
gc.add(Calendar.DAY_OF_MONTH, +38);

让它更清楚一点。 今年复活节是16.04.2017.

因此第一个打印输出正常,'Karfreitag' 是复活节前两天。所以是 14.04.2017.

进入复活节星期一会出现问题。复活节星期一是复活节星期天的次日。不幸的是,我必须添加 +3 天,因为我用 'Karfreitag' 日期覆盖了复活节日期。

所以我想知道是否可以将复活节日期定为固定日期,以便我必须将第 3 行更改为:

gc.add(Calendar.DAY_OF_MONTH, +1);

它认为这可能很容易,但我不知道如何以适当的方式改变它。

您可以这样使用 DateUtils.addDays

DateUtils.addDays(gc.getDate(), -2).getTime()

它需要一个 Date 对象(你可以为此使用 gc.getDate())和 int 天数作为参数添加,还需要 return 一个 Date 对象而不修改你原来的 gc.

System.out.println("Karfreitag;"+dateFormat.format(DateUtils.addDays(gc.getDate(), -2).getTime()));
System.out.println("Ostermontag;"+dateFormat.format(DateUtils.addDays(gc.getDate(), 3).getTime()));
System.out.println("something else;"+dateFormat.format(DateUtils.addDays(gc.getDate(), 38).getTime()));

在 Android 中它可以从 API 级别 3 获得,在 Java 中你必须使用 Apache Commons

由于 add 方法更改了当前日历实例,一种解决方案是使用 clone() 方法创建另一个:

// clone it before changing it
GregorianCalendar other = (GregorianCalendar) gc.clone();

gc.add(Calendar.DAY_OF_MONTH, -2);
System.out.println("Karfreitag;" + dateFormat.format(gc.getTime()));

other.add(Calendar.DAY_OF_MONTH, 1);
System.out.println("Ostermontag;" + dateFormat.format(other.getTime()));

Java新Date/TimeAPI

旧的 classes(DateCalendarSimpleDateFormat)有 lots of problems and design issues,它们正在被新的 APIs.

如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.

如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it ).

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

当您处理日期 (day/month/year) 时,您可以使用 LocalDate class。在这个新的 API 中,classes 是不可变的,所以添加天数的方法总是创建另一个对象:

LocalDate easter = LocalDate.parse("2017-04-16");

// minusDays and plusDays return a new LocalDate, keeping the original unchanged
System.out.println("Karfreitag;" + easter.minusDays(2));
System.out.println("Ostermontag;" + easter.plusDays(1));

输出将是:

Karfreitag;2017-04-14
Ostermontag;2017-04-17

如果您有日、月和年作为 int 值,您可以使用 of 方法创建一个 LocalDate

int tag = 16;
int monat = 4;
int jahr = 2017;
// Easter
LocalDate easter = LocalDate.of(jahr, monat, tag);

转换from/to公历

如果您仍然需要使用 GregorianCalendar,您可以轻松地将它 from/to 转换为新的 API。在 Java 8 中有进行转换的新方法,而在 Java 6/7 ThreeTen Backport 中有 org.threeten.bp.DateTimeUtils class:

// Java 8: convert calendar to local date
LocalDate dt = gc.toZonedDateTime().toLocalDate();

// Java 7: convert calendar to local date
LocalDate dt = DateTimeUtils.toZonedDateTime(gc).toLocalDate();

LocalDate 转换回 GregorianCalendar 有点棘手。 LocalDate 只有日期字段(日、月和年),而 GregorianCalendar 表示 "full date":特定时区的日期和时间。

因此,在将 LocalDate 转换为 GregorianCalendar 时,您必须对时间(小时、分钟等)和时区做出一些假设。一个例子是将时间设置为午夜,并使用 JVM 默认时区:

// Java 8: convert local date to calendar (midnight in JVM default timezone)
GregorianCalendar cal = GregorianCalendar.from(dt.atStartOfDay(ZoneId.systemDefault()));

// Java 7: convert local date to calendar (midnight in JVM default timezone)
GregorianCalendar cal = DateTimeUtils.toGregorianCalendar(dt.atStartOfDay(ZoneId.systemDefault()));

您还可以转换为一天中的任何其他时间并将时区更改为您想要的任何时间:

// set to 10:30 AM in Berlin timezone
dt.atTime(10, 30).atZone(ZoneId.of("Europe/Berlin"));

或者直接使用toZonedDateTime()返回的ZonedDateTime,打印时将LocalDate部分提取出来:

// convert calendar to ZonedDateTime
ZonedDateTime z = gc.toZonedDateTime();

// print just the LocalDate part
System.out.println("Karfreitag;" + z.minusDays(2).toLocalDate());
System.out.println("Ostermontag;" + z.plusDays(1).toLocalDate());

// get the original calendar back
GregorianCalendar cal = GregorianCalendar.from(z);

这个新的 API 有 lots of new types 并允许您为每个案例选择最佳的。

开始使用 java.time.LocalDate。它提供了一个 LocalDate.plusDays(long) 即 return 实例的副本。

Returns a copy of this LocalDate with the specified number of days added.

像这样:

LocalDate tomorrow = LocalDate.now().plusDays(1);

您可以使用 LocalDate.of(int, int, int) 获取实例,例如:

LocalDate date = LocalDate.of(year, month, day);

注意:这是 的较短版本,只是意识到他的回答中有一部分...