Как получить время начала и окончания дня?
Как получить время начала и окончания дня?
код, подобный этому, не является точным:
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();
}