在不使用 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
Easiest way to add a month to a java DATE type without using Calendar or Joda?
提问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 .java
file, 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 numMonths
set 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 Date
and Calendar
.
该java.time类Java中内嵌的8,9 Java的,后来。这些取代了麻烦的旧日期时间类,例如Date
和Calendar
。
If you must inter-operate with an existing Date
object, convert to java.time. The equivalent is Instant
. The Instant
class 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 Instant
is 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 EST
or IST
as they are nottrue time zones, not standardized, and not even unique(!).
以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的伪区域,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/region
America/Montreal
Africa/Casablanca
Pacific/Auckland
EST
IST
ZoneId z = ZoneId.of( "America/Montreal" ) ;
Adjust your Instant
into that time zone, applying a ZoneId
to get a ZonedDateTime
object.
将您调整Instant
到该时区,应用 aZoneId
来获取ZonedDateTime
对象。
ZonedDateTime zdt = instant.atZone( z ) ;
Define six months as a Period
.
将六个月定义为Period
.
Period p = Period.ofMonths( 6 ) ;
Add that Period
object to generate a new ZonedDateTime
object.
添加该Period
对象以生成新ZonedDateTime
对象。
ZonedDateTime later = zdt.plus( p ) ;
See this code run live at 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 LocalDate
class 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 类?
- Java SE 8, Java SE 9, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android, the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9及更高版本
- 内置。
- 具有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- 更高版本的 Android 捆绑实现 java.time 类。
- 对于早期的 Android,ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
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 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。