如何修复GregorianCalendar中的gc.setTime()



这是我的代码中的一部分:

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

让它更清楚一点。Eastersunday是在2017年4月16日。

所以第一份印刷品运行良好,"Karfreitag"是复活节前两天。所以是2017年4月14日。

进入复活节星期一带来了一个问题。复活节是复活节的第二天。不幸的是,我不得不增加+3天,因为我用"Karfreitag"日期覆盖了复活节周日的日期。

所以我想知道是否有可能将复活节的日期改为:

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

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

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新日期/时间API

旧的类(DateCalendarSimpleDateFormat)有很多问题和设计问题,它们正在被新的API所取代。

如果您正在使用Java 8,请考虑使用新的java.timeAPI。与旧的API相比,它更容易,更少的bug和更少的错误。

如果您使用Java 6或7,您可以使用ThreeTen Backport,这是Java 8新的日期/时间类的一个很好的Backport。对于Android,您还需要ThreeTenABP(有关如何使用它的更多信息,请点击此处)。

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

在处理日期(日/月/年)时,可以使用LocalDate类。在这个新的API中,类是不可变的,所以增加天数的方法总是创建另一个对象:

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
奥斯特蒙塔格;2017-04-17

如果将天、月和年作为int值,则可以使用of方法创建LocalDate

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

从GregorianCalendar转换

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

// 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表示"完整日期":特定时区中的日期和时间。

因此,在将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有很多新的类型,可以让你为每种情况选择最好的。

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

返回添加了指定天数的此LocalDate的副本。

像这样:

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

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

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

注:这是雨果答案的简短版本,只要意识到他的答案中有一部分。。。

您可以这样使用DateUtils.addDays

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

它需要一个Date对象(可以使用gc.getDate())和int天数作为参数添加,并且在不修改原始gc的情况下返回Date对象。

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

最新更新