计算3天后;从日期开始,添加到查找窗口

时间:2014-02-06 15:24:10

标签: java date calendar

我尝试根据当前加上30,60,90天之前和之后的3天计算日期窗口。除了这种肮脏的方式,我真的不能用日历做正确的方法。

    public static void main(String []args) throws ParseException {

    Calendar cal = GregorianCalendar.getInstance();
    System.out.println("Curent date is " + cal.getTime() + "\n");
    int []  remainingPeriodArr = {30,60,90,180};
    int []  expiredArr = {30,60,90};

    for(int i = 0; i < remainingPeriodArr.length; i++) {
        getSupportPeriod(remainingPeriodArr[i]);
    }

    for(int i = 0; i < expiredArr.length; i++) {
        getSupportPeriod(expiredArr[i]);
    }
}

public static void getSupportPeriod(int period) {
    Calendar c1 =  GregorianCalendar.getInstance();
    c1.add(Calendar.DATE, -3);
    c1.add(Calendar.DATE, period);
    System.out.println( period + " days from prior window " + c1.getTime() + "\n");

    Calendar c2 =  GregorianCalendar.getInstance();
    c2.add(Calendar.DATE, 3);
//      Date d2 = c2.getTime();
    c2.add(Calendar.DATE, period);
    System.out.println( period+ " days in the future window " + c2.getTime() + "\n");

}

}

3 个答案:

答案 0 :(得分:0)

除了新的JDK8日期库或Joda Time,最简单的方法是以毫秒为单位处理当前时间:

long now = System.currentTimeMilliseconds();
long threeDaysAgoMillis = now - (3 * 24 * 60 * 60 * 1000);
long nowPlus30Millis = now + (30 * 24 * 60 * 60 * 1000);

Date threeDaysAgo = new Date(threeDaysAgoMillis);
Date nowPlus30 = new Date(nowPlus30Millis);

如果您使用的是JDK8,请查看this tutorial。如果您可以使用Joda时间,请查看here

答案 1 :(得分:0)

如果你采用旧的JDK方式,那么请注意以下陷阱:

A)一般避免使用继承的静态方法,但使用具体的值对象类型。

Calendar c1 =  GregorianCalendar.getInstance();

更好用:

GregorianCalendar c1 = new GregorianCalendar();

为什么呢?如果你在泰国,你将不会通过在GregorianCalendar-class上使用静态Calendar方法获得您的方法的格里历。相反,你得到佛教日历。

B)根据您的问题使用特定于域的类型

不幸的是,GregorianCalendar不是一个仅限日期的类型,因此它不能很好地满足您对日期算术的要求。在旧的JDK中根本没有这种类型,所以你必须忍受丑陋的工作。在Java 8中,您可以使用java.time.LocalDate,在JodaTime中您可以使用org.joda.time.LocalDate。在我即将到来的时间库中,您可以使用net.time4j.PlainDate(本月仍会首次发布)。

C)否则尝试模仿普通日期类型

使用GregorianCalendar您需要将所有时间字段清零,即:

gcal.set(year, month, dayOfMonth);
gcal.set(Calendar.HOUR_OF_DAY, 0);
gcal.set(Calendar.MINUTE, 0);
gcal.set(Calendar.SECOND, 0);
gcal.set(Calendar.MILLISECOND, 0);

请注意,这种方法在与时区偏移变化相关的一些罕见情况下并不完美,但在美国和欧洲可能已足够。

如果您评估此类日历对象作为add(Calendar.DATE, period)等附加操作的结果,则只应打印其日期部分并忽略时间部分 - 在大多数情况下,通过根据您的本地或作为日期选择仅限日期的格式ISO-8601格式(主要限于年,月,日)。

如果比较这些日历对象,则不要根据方法getTime()应用比较,但只能通过显式提取年,月和日(写一个专门的Comparator是一个好主意)。

D)避免自制日期/时间算术,信任库

如果您在此期间有夏令时切换,则long nowPlus30Millis = now + (30 * 24 * 60 * 60 * 1000);之类的代码可能会失败。 java.util.GregorianCalendar的add() - 方法可以考虑到这一点,但通常不是自制的算法。

答案 2 :(得分:0)

TL;博士

LocalDate.now().plusDays( 3 )

java.time

现代方法使用 java.time 类。

LocalDate

LocalDate类表示没有时间且没有时区的仅限日期的值。

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜后的几分钟是新的一天,而Montréal Québec中仍然是“昨天”。

如果未指定时区,则JVM会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好明确指定您期望/预期的时区作为参数。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

如果要使用JVM的当前默认时区,请求它并作为参数传递。如果省略,则隐式应用JVM的当前默认值。最好是明确的,因为默认情况下可以在运行时期间由JVM中任何应用程序的任何线程中的任何代码随时更改

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

或指定日期。您可以将月份设置为一个数字,1月至12月的数字为1-12。

LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.

或者,更好的是,使用预定义的Month枚举对象,一年中的每个月一个。提示:在整个代码库中使用这些Month对象,而不仅仅是整数,以使代码更具自我记录功能,确保有效值,并提供type-safety

LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;

数学

添加天数的一种方法是使用LocalDate::plusDays方法。类似于减法。

LocalDate later = ld.plusDays( 3 ) ;
LocalDate earlier = ld.minusDays( 3 ) ;

或者,使用对象来表示要添加或减去的时间跨度。这样做的好处是能够使用变量名称标记您的时间跨度。对于数月 - 天,请使用Period。对于小时 - 分钟 - 秒,请使用Duration

Period periodBookIsLate = Period.ofDays( 3 ) ;
LocalDate dueDate = ld.plus( periodBookIsLate ) ; 

LocalDateRange

您可以在 ThreeTen-Extra 项目中找到有用的LocalDateRange类。

LocalDateRange thirtyDayRange = LocalDateRange.of( ld.minusDays( 30 ) , ld.plusDays( 30 ) ) ; 

了解该类中的方便方法,例如abuts,contains,intersection等。

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore