在不使用 Calendar 或 Joda 的情况下将月份添加到 Java DATE 类型的最简单方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11583829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:40:26  来源:igfitidea点击:

Easiest way to add a month to a java DATE type without using Calendar or Joda?

javadatewebsphere-process-server

提问by antonpug

I am working in an integrated environment (IBM Process Server) and I am not able to import anything, can only use standard java functionality.

我在集成环境 (IBM Process Server) 中工作,但无法导入任何内容,只能使用标准的 Java 功能。

How can I add x number of months to a given date?

如何将 x 个月数添加到给定日期?

回答by ewok

Given that you have Date imported by default, you can add a number of months to the date object by the following:

鉴于默认情况下您已导入 Date,您可以通过以下方式向日期对象添加多个月份:

public void addMonths(Date date, int numMonths){
    date.setMonth((date.getMonth() - 1 + numMonths) % 12 + 1);
}

NOTE

笔记

You can use external classes from Java SE by using their full package name. i.e., even if you cannot add import java.util.Calendar;to the top of you .javafile, you can still create a calendar object by executing java.util.Calendar cal = java.util.Calendar.getInstance();

您可以使用来自 Java SE 的外部类的完整包名。即,即使您不能添加import java.util.Calendar;.java文件的顶部,您仍然可以通过执行来创建日历对象java.util.Calendar cal = java.util.Calendar.getInstance();

回答by ppeterka

@ewok's answer does not work always when going past the year end, only with numMonthsset to values lower or equal to the months until next January:

@ewok 的答案在年终结束时并不总是有效,只有numMonths将值设置为低于或等于直到明年一月的月份

SSCCE:

SSCCE:

public static  void main(String[] args) {
  for(int i=0;i<10; i++) {
    Date date = new Date();
    Date updated = (Date)date.clone();
    addMonths(updated, i);
    System.out.println(" original: " + date+  " adding " +i+ " months: " + updated);
  }
}

public static void addMonths(Date date, int numMonths){
  date.setMonth((date.getMonth() - 1 + numMonths) % 12 + 1);
}

Output:

输出:

original: Sat Aug 24 14:02:17 CEST 2013 adding 0 months: Sat Aug 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 1 months: Tue Sep 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 2 months: Thu Oct 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 3 months: Sun Nov 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 4 months: Tue Dec 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 5 months: Fri Jan 24 14:02:17 CET 2014
original: Sat Aug 24 14:02:17 CEST 2013 adding 6 months: Sun Feb 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 7 months: Sun Mar 24 14:02:17 CET 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 8 months: Wed Apr 24 14:02:17 CEST 2013
original: Sat Aug 24 14:02:17 CEST 2013 adding 9 months: Fri May 24 14:02:17 CEST 2013

Noticethe February, March, etc dates are back in 2013! The code is flawed because of the strange arithmetics... setMonth handles values > 12 too...

注意二月、三月等日期回到 2013 年!由于奇怪的算术,代码有缺陷...... setMonth 也处理大于 12 的值......

Corrected (though still using the deprecated method...):

更正(尽管仍在使用已弃用的方法...):

      date.setMonth((date.getMonth() + numMonths) );

Output:

输出:

original: Sat Aug 24 14:13:09 CEST 2013 adding 0 months: Sat Aug 24 14:13:09 CEST 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 1 months: Tue Sep 24 14:13:09 CEST 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 2 months: Thu Oct 24 14:13:09 CEST 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 3 months: Sun Nov 24 14:13:09 CET 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 4 months: Tue Dec 24 14:13:09 CET 2013
original: Sat Aug 24 14:13:09 CEST 2013 adding 5 months: Fri Jan 24 14:13:09 CET 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 6 months: Mon Feb 24 14:13:09 CET 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 7 months: Mon Mar 24 14:13:09 CET 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 8 months: Thu Apr 24 14:13:09 CEST 2014
original: Sat Aug 24 14:13:09 CEST 2013 adding 9 months: Sat May 24 14:13:09 CEST 2014

Things to consider

需要考虑的事项

  • Last days of months, from the Java doc of setMonth():

    Sets the month of this date to the specified value. This Date object is modified so that it represents a point in time within the specified month, with the year, date, hour, minute, and second the same as before, as interpreted in the local time zone. If the date was October 31, for example, and the month is set to June, then the new date will be treated as if it were on July 1, because June has only 30 days.

  • Still deprecated - Solving the problem properly would be overly time consuming however (exceptional cases, leap days, leap seconds, whatever), not to mention total reinvention of the wheel... Maybe trimming Calendar to the bare minimum, and pasting it into the code would solve it - but even that is not worth the hassle...

  • Should definitely try the second approach what @ewok suggested, the fully qualified classname thing.

  • 几个月的最后几天,来自 setMonth() 的 Java 文档:

    将此日期的月份设置为指定值。修改此 Date 对象,使其表示指定月份内的一个时间点,其中年、日、时、分和秒与以前相同,在本地时区中进行解释。例如,如果日期是 10 月 31 日,并且月份设置为六月,那么新日期将被视为 7 月 1 日,因为六月只有 30 天。

  • 仍然不推荐使用 - 然而,正确解决问题会过于耗时(例外情况,闰日,闰秒,等等),更不用说轮子的彻底改造......也许将日历修剪到最低限度,然后将其粘贴到代码会解决它 - 但即使这样也不值得麻烦......

  • 绝对应该尝试@ewok 建议的第二种方法,即完全限定的类名。

回答by Santhoshle

If you want to implement without calendar use @ewok suggestion if working with deprecated method a problem then use the following code:

如果您想在没有日历的情况下实现使用@ewok 建议,如果使用不推荐使用的方法出现问题,请使用以下代码:

SimpleDateFormat dt1 = new SimpleDateFormat("yyyy-MM-dd");  //Date format
    SimpleDateFormat dt = new SimpleDateFormat("MM");
    Date date = dt1.parse("2013-12-31");
    int dm=0;
    int m = Integer.parseInt(dt.format(date));
    switch(m){
        case 2:
            m = 27;
        break;
        case 4:
        case 6:
        case 9:
        case 11:
            m = 29;
        break;
        default:
            m = 30;
        break;
    }// Closing switch block
    long month = Math.round(1000*60*60*24.25*m);
    long oneMonthTime =  date.getTime()+month;
    System.out.println(dt1.format(oneMonthTime));

This code is not for leap year. I know its non perfect one but still working code.

此代码不适用于闰年。我知道它不完美,但仍在运行代码。

回答by Basil Bourque

tl;dr

tl;博士

myJavaUtilDate.toInstant()                      // Convert troublesome legacy `java.util.Date` object to a modern java.time object, `Instant`.
    .atZone( ZoneId.of( "Pacific/Auckland" ) )  // Adjust that `Instant` object from UTC to a particular time zone thereby instantiating a `ZonedDateTime` object, to determine dates.
    .plus( Period.ofMonths( 6 ) )               // Add six months represented by a `Period` to instantiate another `ZonedDateTime` object.

java.time

时间

The java.timeclasses are built into Java 8, Java 9, and later. These supplant the troublesome old date-time classes such as Dateand Calendar.

java.time类Java中内嵌的8,9 Java的,后来。这些取代了麻烦的旧日期时间类,例如DateCalendar

If you must inter-operate with an existing Dateobject, convert to java.time. The equivalent is Instant. The Instantclass represents a moment on the timeline in UTCwith a resolution of nanoseconds(up to nine (9) digits of a decimal fraction). Convert using new methods added to the old classes.

如果必须与现有Date对象进行互操作,请转换为 java.time。等价物是Instant。该Instant级表示时间轴上的时刻UTC,分辨率为纳秒(最多小数的9个位数)。使用添加到旧类的新方法进行转换。

Instant instant = myJavaUtilDate.toInstant() ;

An Instantis a moment in UTC. Adding six months requires a date. A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris Franceis a new day while still “yesterday” in Montréal Québec.

AnInstant是 UTC 中的一个时刻。添加六个月需要一个日期。时区对于确定日期至关重要。对于任何给定时刻,日期因地区而异。例如,在法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天” 。

Specify a proper time zone namein the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter pseudo-zones such as ESTor ISTas they are nottrue time zones, not standardized, and not even unique(!).

以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的伪区域,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

ZoneId z = ZoneId.of( "America/Montreal" ) ;

Adjust your Instantinto that time zone, applying a ZoneIdto get a ZonedDateTimeobject.

将您调整Instant到该时区,应用 aZoneId来获取ZonedDateTime对象。

ZonedDateTime zdt = instant.atZone( z ) ;

Define six months as a Period.

将六个月定义为Period.

Period p = Period.ofMonths( 6 ) ;

Add that Periodobject to generate a new ZonedDateTimeobject.

添加该Period对象以生成新ZonedDateTime对象。

ZonedDateTime later = zdt.plus( p ) ;

See this code run live at IdeOne.com.

在 IdeOne.com 上实时查看此代码

instant.toString(): 2018-01-31T06:26:34.580Z

zdt.toString(): 2018-01-31T01:26:34.580-05:00[America/Montreal]

p.toString(): P6M

later.toString()2018-07-31T01:26:34.580-04:00[America/Montreal]

Instant.toString(): 2018-01-31T06:26:34.580Z

zdt.toString(): 2018-01-31T01:26:34.580-05:00[美国/蒙特利尔]

p.toString(): P6M

later.toString()2018-07-31T01:26:34.580-04:00[美国/蒙特利尔]

If you need to get back to a value in UTC, extract a Instant.

如果您需要返回 UTC 中的值,请提取Instant.

Instant instant = later.toInstant() ;

If you need a Date, convert. But try to avoid this class if possible.

如果你需要一个Date,转换。但是如果可能的话,尽量避免这个类。

Date d = Date.from( instant ) ;

If you have date-only value without time-of-day, use LocalDate. The LocalDateclass represents a date-only value without time-of-day and without time zone.

如果您有没有时间的仅日期值,请使用LocalDate. 该LocalDate级表示没有时间一天和不同时区的日期,唯一的价值。

LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;  // January 23, 2018.
LocalDate later = ld.plusMonths( 6 ) ;


About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多