Как получить время начала и окончания дня?

Как получить время начала и окончания дня?

код, подобный этому, не является точным:

 private Date getStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 0, 0, 0);
    return calendar.getTime();
}

private Date getEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 23, 59, 59);
    return calendar.getTime();
}

Это неточно для миллисекунды.

Ответ 1

Half-Open

Ответ от mprivat правильный. Его цель - не пытаться достичь конца дня, а сравнивать с "до начала следующего дня". Его идея известна как "полуоткрытый" подход, когда промежуток времени имеет начало , включающее, тогда как окончание является эксклюзивным.

  • В настоящее время структурами даты и времени являются Java (java.util.Date/Calendar и Joda-Time), которые используют миллисекунды с эпохи. Но в Java 8 новые классы JSR 310 java.time. * Используют разрешение наносекунд. Любой код, который вы написали на основе принудительного подсчета в миллисекундах в последний момент дня, был бы некорректным, если переключиться на новые классы.
  • Сравнение данных из других источников становится ошибочным, если они используют другие разрешения. Например, библиотеки Unix обычно используют целые секунды, а базы данных, такие как Postgres, разрешают дату и время в микросекундах.
  • Некоторые изменения летнего времени происходят в полночь, что может еще больше запутать ситуацию.

enter image description here

Joda-Time 2.3 предлагает для этой цели метод получения первого момента дня: withTimeAtStartOfDay(). Аналогично в java.time, LocalDate::atStartOfDay.

Поищите в Qaru слово "joda half-open", чтобы увидеть больше обсуждений и примеров.

Смотрите этот пост, Временные интервалы и другие диапазоны должны быть полуоткрыты, Биллом Шнайдером.

Избегайте устаревших классов даты и времени

Классы java.util.Date и .Calendar печально известны своими проблемами. Избежать их.

Используйте Joda-Time или, предпочтительно, java.time. Инфраструктура java.time является официальным преемником очень успешной библиотеки Joda-Time.

java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Обратно портирован на Java 6 & 7 в проекте ThreeTen-Backport, дополнительно адаптирован для Android в проекте ThreeTenABP.

Instant - это момент времени на UTC с разрешением наносекунд.

Instant instant = Instant.now();

Примените часовой пояс, чтобы получить настенное время для некоторого населенного пункта.

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

Чтобы получить первое время дня, изучите класс LocalDate и его метод atStartOfDay.

ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );

Используя подход Half-Open, получите первый момент следующего дня.

ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );

Table of date-time types in Java, both modern and legacy.

В настоящее время в среде java.time отсутствует класс Interval, как описано ниже для Joda-Time. Однако проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Среди его классов есть Interval. Создайте Interval, передав пару объектов Instant. Мы можем извлечь Instant из наших ZonedDateTime объектов.

Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );

Joda времени

ОБНОВЛЕНИЕ: проект Joda-Time сейчас находится в режиме обслуживания и рекомендует перейти на классы java.time. Я оставляю этот раздел нетронутым для истории.

Joda-Time имеет три класса для представления промежутка времени различными способами: Interval, Period и Duration. Interval имеет определенное начало и конец на временной шкале Вселенной. Это соответствует нашей потребности представлять "день".

Мы называем метод withTimeAtStartOfDay, а не устанавливаем время дня в нули. Из-за перехода на летнее время и других аномалий первый момент дня может не совпадать 00:00:00.

Пример кода с использованием Joda-Time 2.3.

DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );

Если нужно, вы можете преобразовать его в java.util.Date.

java.util.Date date = todayStart.toDate();

Ответ 2

Java 8


public static Date atStartOfDay(Date date) {
    LocalDateTime localDateTime = dateToLocalDateTime(date);
    LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
    return localDateTimeToDate(startOfDay);
}

public static Date atEndOfDay(Date date) {
    LocalDateTime localDateTime = dateToLocalDateTime(date);
    LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
    return localDateTimeToDate(endOfDay);
}

private static LocalDateTime dateToLocalDateTime(Date date) {
    return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}

private static Date localDateTimeToDate(LocalDateTime localDateTime) {
    return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}

Обновление: Я добавил эти 2 метода моих классов Java Utility здесь

Он находится в Центральном репозитории Maven:

<dependency>
  <groupId>com.github.rkumsher</groupId>
  <artifactId>utils</artifactId>
  <version>1.3</version>
</dependency>

Java 7 и ранее


С Apache Commons

public static Date atEndOfDay(Date date) {
    return DateUtils.addMilliseconds(DateUtils.ceiling(date, Calendar.DATE), -1);
}

public static Date atStartOfDay(Date date) {
    return DateUtils.truncate(date, Calendar.DATE);
}

Без Apache Commons

public Date atEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 23);
    calendar.set(Calendar.MINUTE, 59);
    calendar.set(Calendar.SECOND, 59);
    calendar.set(Calendar.MILLISECOND, 999);
    return calendar.getTime();
}

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

Ответ 3

в getEndOfDay, вы можете добавить:

calendar.set(Calendar.MILLISECOND, 999);

Хотя математически говоря, вы не можете указать конец дня, кроме как сказать это "до начала следующего дня".

Поэтому вместо того, чтобы говорить, if(date >= getStartOfDay(today) && date <= getEndOfDay(today)), вы должны сказать: if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow)). Это гораздо более четкое определение (и вам не нужно беспокоиться о миллисекундной точности).

Ответ 4

java.time

Использование java.time фреймворка, встроенного в Java 8.

import java.time.LocalTime;
import java.time.LocalDateTime;

LocalDateTime now = LocalDateTime.now(); // 2015-11-19T19:42:19.224
// start of a day
now.with(LocalTime.MIN); // 2015-11-19T00:00
now.with(LocalTime.MIDNIGHT); // 2015-11-19T00:00
// end of a day
now.with(LocalTime.MAX); // 2015-11-19T23:59:59.999999999

Ответ 5

Дополнительный способ поиска начала дня с java8 java.time.ZonedDateTime вместо прохождения LocalDateTime - это просто усечение входа ZonedDateTime в DAYS:

zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS );

Ответ 6

Для java 8 работают следующие однострочные операторы. В этом примере я использую часовой пояс UTC. Пожалуйста, подумайте о том, чтобы изменить TimeZone, который вы использовали в настоящее время.

System.out.println(new Date());

final LocalDateTime endOfDay       = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
final Date          endOfDayAsDate = Date.from(endOfDay.toInstant(ZoneOffset.UTC));

System.out.println(endOfDayAsDate);

final LocalDateTime startOfDay       = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
final Date          startOfDayAsDate = Date.from(startOfDay.toInstant(ZoneOffset.UTC));

System.out.println(startOfDayAsDate);

Если нет разницы во времени с выходом. Попробуйте: ZoneOffset.ofHours(0)

Ответ 7

Java 8 или ThreeTenABP

ZonedDateTime

ZonedDateTime curDate = ZonedDateTime.now();

public ZonedDateTime startOfDay() {
    return curDate
    .toLocalDate()
    .atStartOfDay()
    .atZone(curDate.getZone())
    .withEarlierOffsetAtOverlap();
}

public ZonedDateTime endOfDay() {

    ZonedDateTime startOfTomorrow =
        curDate
        .toLocalDate()
        .plusDays(1)
        .atStartOfDay()
        .atZone(curDate.getZone())
        .withEarlierOffsetAtOverlap();

    return startOfTomorrow.minusSeconds(1);
}

// based on https://stackoverflow.com/a/29145886/1658268

LocalDateTime

LocalDateTime curDate = LocalDateTime.now();

public LocalDateTime startOfDay() {
    return curDate.atStartOfDay();
}

public LocalDateTime endOfDay() {
    return startOfTomorrow.atTime(LocalTime.MAX);  //23:59:59.999999999;
}

// based on https://stackoverflow.com/a/36408726/1658268

Надеюсь, это поможет кому-то.

Ответ 8

Я попробовал этот код, и он хорошо работает!

final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
final ZonedDateTime startofDay =
    now.toLocalDate().atStartOfDay(ZoneOffset.UTC);
final ZonedDateTime endOfDay =
    now.toLocalDate().atTime(LocalTime.MAX).atZone(ZoneOffset.UTC);

Ответ 9

Еще одно решение, которое не зависит от каких-либо фреймворков:

static public Date getStartOfADay(Date day) {
    final long oneDayInMillis = 24 * 60 * 60 * 1000;
    return new Date(day.getTime() / oneDayInMillis * oneDayInMillis);
}

static public Date getEndOfADay(Date day) {
    final long oneDayInMillis = 24 * 60 * 60 * 1000;
    return new Date((day.getTime() / oneDayInMillis + 1) * oneDayInMillis - 1);
}

Обратите внимание, что он возвращает время, основанное на UTC

Ответ 10

Я знаю, что это немного поздно, но в случае Java 8, если вы используете OffsetDateTime (который предлагает много преимуществ, таких как TimeZone, наносекунды и т.д.), Вы можете использовать следующий код:

OffsetDateTime reallyEndOfDay = someDay.withHour(23).withMinute(59).withSecond(59).withNano(999999999);
// output: 2019-01-10T23:59:59.999999999Z

Ответ 11

В дополнение к ответу @BasilBourque:

Немного тяжелый, но безопасный метод для установки минимального времени (только для начала):

cal.setTime(...);
cal.set(Calendar.HOUR_OF_DAY, cal.getMinimum(Calendar.HOUR_OF_DAY));
cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));

Это гарантирует, что минимальные значения будут таковыми для Календаря.

Ответ 12

Я знаю, что это старый вопрос, но это мое предложение об этом, надеюсь, что это может вам помочь:

  • Используя JodaTime, мы можем сделать это:

    public static final Integer CURRENT_YEAR = DateTime.now().getYear();
    
    public static final Integer CURRENT_MONTH = DateTime.now().getMonthOfYear();
    
    public static final Integer CURRENT_DAY = DateTime.now().getDayOfMonth();
    
    public static final Integer LAST_HOUR_OF_CURRENT_DAY = DateTime.now().hourOfDay().getMaximumValue();
    
    public static final Integer FIRST_HOUR_OF_CURRENT_DAY = DateTime.now().hourOfDay().getMinimumValue();
    
    public static final Integer LAST_MINUTE_OF_CURRENT_HOUR = DateTime.now().minuteOfHour().getMaximumValue();
    
    public static final Integer FIRST_MINUTE_OF_CURRENT_HOUR = DateTime.now().minuteOfHour().getMinimumValue();
    
    public static final Integer LAST_SECOND_OF_CURRENT_MINUTE = DateTime.now().secondOfMinute().getMaximumValue();
    
    public static final Integer FIRST_SECOND_OF_CURRENT_MINUTE = DateTime.now().secondOfMinute().getMinimumValue();
public static DateTime getFirstDateOfDay() {
        return new DateTime(CURRENT_YEAR, CURRENT_MONTH, CURRENT_DAY,
                FIRST_HOUR_OF_CURRENT_DAY, FIRST_MINUTE_OF_CURRENT_HOUR,
                FIRST_SECOND_OF_CURRENT_MINUTE);
    }

    public static DateTime getLastDateOfDay() {
        return new DateTime(CURRENT_YEAR, CURRENT_MONTH, CURRENT_DAY,
                LAST_HOUR_OF_CURRENT_DAY, LAST_MINUTE_OF_CURRENT_HOUR,
                LAST_SECOND_OF_CURRENT_MINUTE);
    }

Как описывается в моей маленькой сущности здесь, на github: joda time, java8 date time (utils)

Ответ 13

public static Date beginOfDay(Date date) {
    Calendar cal = Calendar.getInstance();
    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();
}

public static Date endOfDay(Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);
    cal.set(Calendar.MILLISECOND, 999);

    return cal.getTime();
}

Ответ 14

Я пробовал этот код, и он работает хорошо!

Date d= new Date();
GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
String s_d=d.getYear()+"-"+(d.getMonth()+1)+"-"+d.getDay();
DateFormat dateFormat = DateFormat.getDateInstance();
try {
// for the end of day :
c.setTime(dateFormat.parse(s_d+" 23:59:59"));
// for the start of day:
//c.setTime(dateFormat .parse(s_d+" 00:00:00"));
} catch (ParseException e) {
e.printStackTrace();
}