Как обрезать минуты и часы и секунды от объекта Date? - PullRequest
11 голосов
/ 05 мая 2010

Мне нужно составить карту, где Даты являются ключами. 2 объекта даты равны, если они имеют одинаковое значение getTime() метода.

Меня интересуют только год, месяц и день. Как я могу trim ненужные часы и минуты, чтобы получить «четкие» даты?

Ответы [ 6 ]

24 голосов
/ 05 мая 2010

Вы можете создать 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 
3 голосов
/ 05 мая 2010

Используйте пользовательский 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 и т. Д.

1 голос
/ 25 октября 2016

ТЛ; др

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

Подробнее

В Вопросе и других ответах используются устаревшие старые классы даты и времени, которые оказались плохо продуманными, запутанными и проблемными. Теперь наследие, вытесненное классами java.time.

Instant усечено

Чтобы более прямо ответить на вопрос:

  1. Конвертировать в java.time, с java.util.Date до java.time.Instant.
  2. Сокращение до даты.

Конвертировать с помощью новых методов, добавленных к старым классам.

Instant instant = myUtilDate.toInstant();

Функция усечения встроена в класс Instant. Класс Instant представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).

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

ZonedDateTime & LocalDate

Но у подхода выше есть проблемы. И java.util.Date, и Instant представляют собой момент времени на 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 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , который теперь находится в режиме обслуживания , рекомендует перейти на java.time.

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Где взять классы java.time?

  • Java SE 8 и SE 9 и более поздние
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time перенесена в Java 6 и 7 в ThreeTen-Backport .
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

1 голос
/ 05 мая 2010
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));
0 голосов
/ 07 декабря 2016

Предложенное решение не работает в Android, так как оно застряло на Java 7, поэтому в Календаре глючит ошибка. В других решениях также были ошибки, поскольку они не учитывали смещение TimeZone, или проблемы с переполнением int перед преобразованием в long.

Это решение похоже на работу:

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;
}
0 голосов
/ 05 мая 2010

Просто конвертируйте ваши Date объекты в одинаковые, если они имеют одинаковый год, месяц и день:

public static Date convertDate(Date oldDate) {
    final long oneDay = 1000 * 60 * 60 * 24;
    long newDate = oldDate.getTime() / oneDay;
    return new Date( newDate * oneDay );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...