【问题标题】:Add 30 days to Date in java在java中将30天添加到日期
【发布时间】:2012-07-30 19:04:11
【问题描述】:

为什么当我在今天加上 30 天时,我得到了今天 - 30,而当我加上 20 时,它增加了??

这是一个示例

import java.text.DateFormat;
import java.util.Date;

public class DatePlus
{

    public static void main(String[] args)
    {
        Date now = new Date();
        Date now1 = new Date();
        Date now2 = new Date();
        DateFormat currentDate = DateFormat.getDateInstance();

        Date addedDate1 = addDays(now2, 20);
        Date addedDate2 = addDays(now1, 30);
        System.out.println(currentDate.format(now));
        System.out.println(currentDate.format(addedDate1));
        System.out.println(currentDate.format(addedDate2));
    }

    public static Date addDays(Date d, int days)
    {
        d.setTime(d.getTime() + days * 1000 * 60 * 60 * 24);
        return d;
    }
}

“这是控制台”

Jul 30, 2012
Aug 19, 2012
Jul 10, 2012

【问题讨论】:

标签: java


【解决方案1】:

使用日历。 http://docs.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html

伪代码:

Calendar c= Calendar.getInstance();
c.add(Calendar.DATE, 30);
Date d=c.getTime();

【讨论】:

  • 这个。 Calendar 是管理日期的好方法,您可以从中获取 Date 对象。
  • 对不起作用的代码有很多赞成! DAY_OF_WEEK_IN_MONTH 是非常错误的字段添加到。日期
  • 没错 ;-) .. 这就是我提到“伪”的原因,让我修复它
  • 仅供参考,来自 JavaDoc re DATE -- “这是 DAY_OF_MONTH 的同义词”
  • 仅供参考,存在严重缺陷的日期时间类,例如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 现在是 legacy,被 Java 8 及更高版本中内置的 java.time 类所取代.
【解决方案2】:

这是因为30 * 1000 * 60 * 60 * 24 会溢出Integer.MAX_VALUE,而20 * 1000 * 60 * 60 * 24 不会。

【讨论】:

    【解决方案3】:
    1. Date 与人类使用的任何日历系统无关。它只代表时间点。给Date加30天没有意义,就像给red颜色加20一样。

    2. 添加1000 * 60 * 60 * 24 的常用方法是错误的。您正在添加 86400 秒,但一天不一定长 86400 秒。由于,它可能会更长或更短一小时。由于闰秒,它可能会更长或更短一秒。

    3. 应该做的是将Date 转换为Calendar(它实际上代表一些日历系统,例如GregorianCalendar。然后只需添加天数:

      Calendar calendar = new GregorianCalendar(/* remember about timezone! */);
      calendar.setTime(date);
      calendar.add(Calendar.DATE, 30);
      date = calendar.getTime();
      
    4. 使用来自 Apache Commons Lang 的 DateUtils.addDays()

      DateUtils.add(date, 30);
      

      这不违反上面写的内容,它在下面转换为Calendar

    5. 或者完全避开这个地狱,去Joda Time

    【讨论】:

    【解决方案4】:

    days 是一个整数。

    30 * 1000 * 60 * 60 * 24 是 2,592,000,000,大于 2,147,483,647(Java 中最大的 int)。你有一个缓冲区溢出,你的结果是一个相当小的负数(以二进制检查,转换回 int 作为 2 补码)

    简单的解决方法是将其中一个值转换为 long,以便表达式的结果存储为 long,这样可以保存该值而不会溢出。

     (long) days * 1000L * 60 * 60 * 24
    

    始终建议使用 Calendar 或其他 api(我听说过 JodaTime,但没有使用它)来操作日期。

    【讨论】:

      【解决方案5】:

      tl;博士

      LocalDate.now().plusDays( 30 )
      

      详情

      正如其他人指出的,具体问题是 32 位整数的溢出。

      该代码也忽略了时区的关键问题。

      更大的问题是尝试滚动你自己的日期时间计算,而不是使用像样的库。

      java.time

      Java 8 中内置的 java.time 类,后来取代了麻烦的旧日期时间类。

      Instant 是 UTC 时间线上的时刻,分辨率为纳秒。

      Instant now = Instant.now();  
      

      应用时区以获得ZonedDateTime

      ZoneId zoneId = ZoneId.of( "America/Montreal" );
      ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
      

      现在添加您的 30 天。让 java.time 处理夏令时 (DST) 等异常情况。

      ZonedDateTime zdtLater = zdt.plusDays( 30 );
      

      或者你的意思是一个月。让 java.time 处理不同长度月份的详细信息。

      ZonedDateTime zdtMonthLater = zdt.plusMonths( 1 );
      

      有关在新旧类型之间转换的信息,请参阅this Question。查看添加到旧类的新方法,例如:

      java.util.Date utilDate = java.util.Date.from( zdt.toInstant() );
      java.util.Calendar utilCalendar = java.util.GregorianCalendar.from( ZonedDateTime );
      

      如果您需要仅日期值,请使用 LocalDate。与上述相同的想法,添加几天或几个月。


      关于java.time

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

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

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

      您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

      从哪里获得 java.time 类?

      • Java SE 8Java SE 9 及更高版本
        • 内置。
        • 标准 Java API 的一部分,带有捆绑实现。
        • Java 9 添加了一些小功能和修复。
      • Java SE 6Java SE 7
      • Android
        • java.time 类的 Android 捆绑包实现的更高版本。
        • 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

      ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

      【讨论】:

        【解决方案6】:

        您在计算中遇到整数溢出。天数 * 1000 * 60 * 60 * 24 的值大于天数 = 30 时允许有符号整数的最大值,但天数 = 20 时则不允许。当您递增一个有符号整数时,它的最大可能值,而不是增加值,符号翻转并变为负数!这就是您的日期倒退的原因 - 您正在向其添加一个负数。

        要解决这个问题,您可以使用 long 数据类型,它的最大值比整数大得多,如下所示:

        long secondsToAdd = days;
        secondsToAdd *= (1000*60*60*24);
        d.setTime(d.getTime() + secondsToAdd);
        

        【讨论】:

          【解决方案7】:

          使用此功能:

          public static String addToCurrentDate(String format,int day,int month,int year){
          
                  DateFormat dateFormat = new SimpleDateFormat(format);
          
                  Calendar calendarInstance = Calendar.getInstance();
                  calendarInstance.add(Calendar.YEAR, year);
                  calendarInstance.add(Calendar.MONTH, month);
                  calendarInstance.add(Calendar.DATE, day);
                  return dateFormat.format(calendarInstance.getTime());
              }
          

          【讨论】:

          • 请不要教年轻人使用陈旧而臭名昭著的SimpleDateFormat类。至少不是第一选择。而且不是没有任何保留。今天我们在java.time, the modern Java date and time API 和它的DateTimeFormatter 中做得更好。
          • 感谢指出,其实这段代码是用来构建安卓应用的。在 android 中,大多数新的 java API 需要最新的 Android OS API 级别。所以最好使用旧的 java 类来支持所有旧设备。
          猜你喜欢
          • 1970-01-01
          • 2017-12-03
          • 2013-06-11
          • 1970-01-01
          • 2010-12-09
          • 2015-12-16
          • 2017-01-20
          • 1970-01-01
          相关资源
          最近更新 更多