如何从Date对象中修剪分钟,小时和秒?

时间:2010-05-05 17:29:05

标签: java date

我需要制作日期是键的地图。如果2个日期对象具有相同的getTime()方法值,则它们是等于的。

我只对年,月,日感兴趣。我如何trim不必要的时间和分钟才能获得“明确”的日期?

6 个答案:

答案 0 :(得分:23)

您可以创建trim方法:

public static Date trim(Date date) {
      Calendar cal = Calendar.getInstance();
      cal.clear(); // as per BalusC comment.
      cal.setTime( date );
      cal.set(Calendar.HOUR_OF_DAY, 0);
      cal.set(Calendar.MINUTE, 0);
      cal.set(Calendar.SECOND, 0);
      cal.set(Calendar.MILLISECOND, 0);
      return cal.getTime();
 }

并使用它:

 map.put( trim( aDate ), xyz() );

...

 map.get( trim( otherDate ));

这是一个完整的工作样本:

import java.util.Calendar;
import java.util.Date;
import static java.util.Calendar.*;
import static java.lang.System.out;


public class DateTest {
    public static void main( String [] args )  throws InterruptedException {
            Date date = new Date();
            Thread.sleep(1);
            Date other = new Date();
            out.printf("equals? = %s, hashCode? = %s %n", (date.equals(other)), (date.hashCode() == other.hashCode()));

            Date todayeOne = trim( date );
            Date todayTwo  = trim( date );


            out.printf("equals? = %s, hashCode? = %s %n", (todayeOne.equals(todayTwo)), (todayeOne.hashCode() == todayTwo.hashCode()));

    }

    public static Date trim(Date date) {
          Calendar cal = Calendar.getInstance();
          cal.setTime( date );
          cal.set(HOUR_OF_DAY, 0);
          cal.set(MINUTE, 0);
          cal.set(SECOND, 0);
          cal.set(MILLISECOND, 0);
          return cal.getTime();
     }

}

输出:

$ java DateTest 
equals? = false, hashCode? = false 
equals? = true, hashCode? = true 

答案 1 :(得分:3)

Comparator<Date>使用自定义TreeMap<Date,V>

    Comparator<Date> ymdComparator = new Comparator<Date>() {
        @Override public int compare(Date d1, Date d2) {
            return 
                d1.getYear() < d2.getYear() ? -1 :
                d1.getYear() > d2.getYear() ? +1 :
                d1.getMonth() < d2.getMonth() ? -1 :
                d1.getMonth() > d2.getMonth() ? +1 :
                d1.getDay() < d2.getDay() ? -1 :
                d1.getDay() > d2.getDay() ? +1 :
                0;
        }
    };

    SortedMap<Date,V> map = new TreeMap<Date,V>(ymdComparator);

哦,java.util.Date很糟糕,使用Joda Time等等。

答案 2 :(得分:1)

long time1 = myDate1.getTime()/(1000*60*60*24);
long time2 = myDate2.getTime()/(1000*60*60*24);
if (time1 == time2)
    // equal!

这会推动小数点以下的无效值,然后整数除法将其截断,因此只保留日级别及更高级别的值。

如果您想再次制作这些日期,只需将偏移量应用回截断值:

myDate1.setTime(time1 * (1000*60*60*24));
myDate2.setTime(time2 * (1000*60*60*24));

答案 3 :(得分:1)

TL;博士

LocalDate ld =
    myUtilDate.toInstant()
              .atZone( ZoneId.of( "America/Montreal" ) )
              .toLocalDate();

详细

问题和其他答案使用过时的旧日期时间类,这些类已被证明设计不当,令人困惑且麻烦。现在是遗留的,取而代之的是java.time类。

Instant截断

更直接地解决问题:

  1. 转换为java.time,从java.util.Date转换为java.time.Instant
  2. 截断日期。
  3. 通过添加到旧类的新方法进行转换。

    Instant instant = myUtilDate.toInstant();
    

    截断功能内置于Instant类中。 Instant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

    Instant instantTruncated = instant.truncatedTo( ChronoUnit.DAYS );
    

    ZonedDateTime&amp; LocalDate

    但上述方法存在问题。 java.util.DateInstant都代表UTC时间轴上的时刻,而不是特定时区。因此,如果您删除时间,或将其设置为00:00:00,您将得到一个仅在UTC中有意义的日期。如果你的意思是奥克兰新西兰或蒙特利尔魁北克的日期,你的日期可能错了。

    因此,更好的方法是将所需/预期的时区应用于Instant以获得ZonedDateTime

    另一个问题是我们不恰当地使用日期时间对象来表示仅限日期的值。相反,我们应该使用仅限日期的类。如果您想要的只是日期,我们应该从ZonedDateTime提取LocalDate

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

    ZoneId z = ZoneId.of( "America/Montreal" );
    ZonedDateTime zdt = instant.atZone( z );
    LocalDate ld = zdt.toLocalDate();
    

    关于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

答案 4 :(得分:0)

如果年份,月份和日期相同,只需将Date个对象转换为相等:

public static Date convertDate(Date oldDate) {
    final long oneDay = 1000 * 60 * 60 * 24;
    long newDate = oldDate.getTime() / oneDay;
    return new Date( newDate * oneDay );
}

答案 5 :(得分:0)

建议的解决方案在Android中不起作用,因为它停留在Java 7上,所以Calendar是错误的。其他解决方案也存在错误,因为它们没有考虑到TimeZone偏移,或者在转换为long之前遇到int溢出问题。

此解决方案似乎有效:

public static final long MILLISECONDS_PER_DAY=(1000L * 60L * 60L * 24L);

public static long convertDate(Date d) {
    TimeZone tz = TimeZone.getDefault();
    long val = d.getTime() + tz.getOffset(d.getTime()); /*local timezone offset in ms*/
    return val / MILLISECONDS_PER_DAY;
}

public static Date convertDate(long date) {
    TimeZone tz = TimeZone.getDefault();
    Date d=new Date();
    d.setTime(date*MILLISECONDS_PER_DAY-tz.getOffset(d.getTime()));
    return d;
}