【问题标题】:How to calculate properly actual month count between 2 dates?如何正确计算两个日期之间的实际月数?
【发布时间】:2012-11-01 20:28:36
【问题描述】:

我遵循方法getDiffDateMap 计算两个日期之间的差异并返回整数的Map,分别代表毫秒、秒、分钟、小时、天、月和年。

public static Map<Integer, String> getDiffDateMap(String dateA, String dateB) {

    Calendar cal = Calendar.getInstance();      
    Map<Integer,String> out = new LinkedHashMap<Integer, String>();
    long timeInMillA = 0;
    long timeInMillB = 0;

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 

    Date convertedDateA;
    Date convertedDateB;



    try {
        convertedDateA = dateFormat.parse(dateA);           
        cal.setTime(convertedDateA);
        timeInMillA = cal.getTimeInMillis();


        convertedDateB = dateFormat.parse(dateB);           
        cal.setTime(convertedDateB);
        timeInMillB = cal.getTimeInMillis();

    } catch (ParseException e) {
        e.printStackTrace();
    } 

    long mili = timeInMillB - timeInMillA;
    long sec = mili/1000;
    long min = sec/60;
    long hour = min/60;
    long day = hour/24;
    long week = day/7;
    long month = day/31; // ????
    long year = month/12;

    out.put(7, mili + "");
    out.put(6, sec + "");
    out.put(5, min + "");
    out.put(4, hour + "");
    out.put(3, day + "");
    out.put(2, week + "");
    out.put(1, month + "");
    out.put(0, year + "");

    return out;
}

我的问题是根据实际天数计算月份:

long month = day/31; // or 30

例如:

Map<Integer,String> out = getDiffInMillsec("2012-9-01 20:9:01", "2012-10-01 20:10:01");

    System.out.println(Arrays.asList(out)); 

我得到输出:[{7=2592060000, 6=2592060, 5=43201, 4=720, 3=30, 2=4, 1=0, 0=0}] 其中1 是月数,它是 0。因为差异只有 30 天。我需要添加什么流程来解决这个问题?有什么建议吗?

【问题讨论】:

  • 您的字符串示例不一致。第一个的分钟是一个数字,没有零,而其他 1-9 的值有前导零。

标签: java android date


【解决方案1】:

我遵循了 getDiffDateMap 方法,该方法计算两个日期之间的差异,并返回分别表示毫秒、秒、分钟、小时、天、月和年的整数映射。

不要重新发明轮子:)

Joda Time 有代码可以完成所有这些以及更多工作。例如:

LocalDateTime start = ...;
LocalDateTime end = ...;
Period difference = new Period(start, end, PeriodType.yearMonthDayTime());
int months = difference.getMonths(); // etc

请注意,当您刚刚将差异转换为毫秒数时,您无法获得月数 - 因为月数将取决于开始/结束日期。 (例如,30 天可能是也可能不是一个月……)

我强烈建议您在整个 Java 代码中使用 Joda Time,而不是 java.util.*。这是一个好多更好的 API,希望这意味着您很少需要编写自己的日期/时间处理代码。

【讨论】:

  • 谢谢,Note that you can't get at the number of months when you've just converted the different to a number of milliseconds 是的,我知道。我正在寻找不使用额外jar(适用于android)的方式。在我的代码中,我仍然有 Date convertedDateADate convertedDateB
  • @Fess:好吧,如果你使用的是java.util.Date,那么首先你需要决定你所在的时区。但真的,请不要为了避免依赖而重新发明这个轮子。日期和时间计算很难可靠地正确计算 - 使用 Joda Time 后,您的代码最终也会变得更加清晰。
  • 好的,如果我还没有看到任何其他方法可以很好地做到这一点,我会使用 Joda Time。谢谢
  • 我没有看到Period(start, end, ... 的任何解决方案。例如 "01-09-2012 20:9:01", "01-10-2012 20:9:01" 作为开始和结束我预计 1 个月,30 天,720 小时,但我实际上有 1 个月,0,天,0 小时,0 分钟......
  • @Fess:你为什么会期待 1 个月零 30 天?这两个日期正好相差一个月!如果您尝试获取 totals,那么您应该多次调用 new Period,每次使用一个单位 PeriodType。
【解决方案2】:

我建议使用JodaTime#Months

这有一个功能,例如:

    static Months   monthsBetween(ReadableInstant start, ReadableInstant end) 

创建一个表示两个指定日期时间之间的整月数的月份。

    static Months   monthsBetween(ReadablePartial start, ReadablePartial end) 

创建一个表示两个指定部分日期时间之间的整月数的月份。

【讨论】:

    【解决方案3】:

    我只想在 Jon Skeet 的帮助下总结我们之前谈过的所有内容,这是一个答案,我使用了 JodaTimenew Period 每个日期值:

    import org.joda.time.LocalDateTime;
    import org.joda.time.Period;
    import org.joda.time.PeriodType;
    
    ....
        public static Map<Integer, String> getDateTimeDiffMap(String dateA, String dateB) {
    
        Calendar cal = Calendar.getInstance();
        Map<Integer,String> out = new LinkedHashMap<Integer, String>();
    
        long timeInMillA = 0;
        long timeInMillB = 0;
    
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); 
    
        Date convertedDateA;
        Date convertedDateB;
    
        try {
        convertedDateA = dateFormat.parse(dateA);           
        cal.setTime(convertedDateA);
        timeInMillA = cal.getTimeInMillis();
    
    
        convertedDateB = dateFormat.parse(dateB);           
        cal.setTime(convertedDateB);
        timeInMillB = cal.getTimeInMillis();
    
    } catch (ParseException e) {
        e.printStackTrace();
    } 
    
    
        LocalDateTime startA = new LocalDateTime(timeInMillA);
        LocalDateTime startB = new LocalDateTime(timeInMillB);
    
        Period difference = new Period(startA, startB, PeriodType.days());
        int day = difference.getDays();
    
        difference = new Period(startA, startB, PeriodType.months());
        int month = difference.getMonths();
    
        difference = new Period(startA, startB, PeriodType.years());
        int year = difference.getYears();
    
        difference = new Period(startA, startB, PeriodType.weeks());
        int week = difference.getWeeks();
    
        difference = new Period(startA, startB, PeriodType.hours());
        int hour = difference.getHours();
    
        difference = new Period(startA, startB, PeriodType.minutes());
        long min = difference.getMinutes();
    
        difference = new Period(startA, startB, PeriodType.seconds());
        long sec = difference.getSeconds();
    
        //difference = new Period(startA, startB, PeriodType.millis());
        long mili = timeInMillB - timeInMillA;  
    
    
        out.put(7, mili + "");
        out.put(6, sec + "");
        out.put(5, min + "");
        out.put(4, hour + "");
        out.put(3, day + "");
        out.put(2, week + "");
        out.put(1, month + "");
        out.put(0, year + "");      
    
        return out;
    }
    

    例如对于“01-09-2012 20:9:01”、“01-10-2012 20:9:01”,我得到输出:

    year=0;
    month = 1;
    day=30;
    hour=720;
    ...
    

    【讨论】:

      【解决方案4】:

      java.time

      java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,改用modern Date-Time API*

      另外,下面引用的是来自home page of Joda-Time的通知:

      请注意,从 Java SE 8 开始,用户被要求迁移到 java.time (JSR-310) - JDK 的核心部分,它取代了这个项目。

      使用现代日期时间 API java.time 的解决方案:

      import java.time.LocalDateTime;
      import java.time.format.DateTimeFormatter;
      import java.time.temporal.ChronoUnit;
      import java.util.LinkedHashMap;
      import java.util.Locale;
      import java.util.Map;
      
      public class Main {
          public static void main(String[] args) {
              // Test
              System.out.println(getDiffDateMap("2012-9-01 20:9:01", "2012-10-01 20:10:01"));
          }
      
          public static Map<Integer, String> getDiffDateMap(String dateA, String dateB) {
              Map<Integer, String> out = new LinkedHashMap<Integer, String>();
              DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH);
              LocalDateTime ldtA = LocalDateTime.parse(dateA, dtf);
              LocalDateTime ldtB = LocalDateTime.parse(dateB, dtf);
      
              out.put(7, String.valueOf(ChronoUnit.MILLIS.between(ldtA, ldtB)));
              out.put(6, String.valueOf(ChronoUnit.SECONDS.between(ldtA, ldtB)));
              out.put(5, String.valueOf(ChronoUnit.MINUTES.between(ldtA, ldtB)));
              out.put(4, String.valueOf(ChronoUnit.HOURS.between(ldtA, ldtB)));
              out.put(3, String.valueOf(ChronoUnit.DAYS.between(ldtA, ldtB)));
              out.put(2, String.valueOf(ChronoUnit.WEEKS.between(ldtA, ldtB)));
              out.put(1, String.valueOf(ChronoUnit.MONTHS.between(ldtA, ldtB)));
              out.put(0, String.valueOf(ChronoUnit.YEARS.between(ldtA, ldtB)));
      
              return out;
          }
      }
      

      输出:

      {7=2592060000, 6=2592060, 5=43201, 4=720, 3=30, 2=4, 1=1, 0=0}
      

      ONLINE DEMO

      Trail: Date Time 了解有关现代日期时间 API 的更多信息。


      * 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个Android项目工作并且您的Android API级别仍然不符合Java-8,请检查Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

      【讨论】:

        【解决方案5】:
            try {
                String user = request.getParameter("uname");
                out.println(user); 
                String pass = request.getParameter("pass");
                out.println(pass);
                java.sql.Date sqlDate = new java.sql.Date(new java.util.Date().getTime());
        
                Class.forName( "com.mysql.jdbc.Driver" );
                Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/trans","root","root" ) ;
                Statement st = conn.createStatement(); 
        
                String sql = "insert into purch (cd,cust,dateof) values('" + user + "','" + pass + "', '" + sqlDate + "')";
                st.executeUpdate(sql);
        
                Date date = new Date();
                String modifiedDate= new SimpleDateFormat("-MM-").format(date);
                String dd = modifiedDate.toString();
                String da = "ai";
                out.println(dd);
        
                PreparedStatement statement = conn.prepareStatement("select * from purch where  dateof LIKE ? and cd = ?");    
                statement.setString(1,"%" + dd + "%");
                statement.setString(2,"" + da + "");
                ResultSet rs = statement.executeQuery();
        
        
                if(rs != null) {
                while(rs.next()) {
                    out.println(rs.getString("cd"));
                    out.println(rs.getString("cust"));
                    out.println(rs.getString("dateof"));
                }
                }  
            }catch(Exception e) {
                System.out.println(e.toString());
            } 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-06
          • 2021-07-20
          • 2019-06-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多