Получение компонента времени Java Дата или Календарь
Есть ли простой или элегантный способ захватить только часть времени (часы/минуты/секунды/миллисекунды) части даты Java (или Календарь, это для меня не имеет значения)? Я ищу хороший способ отдельно рассмотреть дату (год/месяц/день) и части времени суток, но, насколько я могу судить, я застрял в доступе к каждому полю отдельно.
Я знаю, что могу написать свой собственный метод для индивидуального захвата полей, которые мне интересны, но я буду делать это как статический полезный метод, который является уродливым. Кроме того, я знаю, что объекты Date и Calendar имеют миллисекундную точность, но я не вижу способа получить доступ к компоненту миллисекунд в любом случае.
Изменить:. Мне было не совсем понятно: использование одного из Date:: getTime() или Calendar:: getTimeInMillis для меня не очень полезно, поскольку они возвращают число миллисекунд с тех пор эпоху (представленную этой датой или календарем), которая фактически не отделяет время суток от остальной информации.
@Jherico ответ - самая близкая вещь, я думаю, но определенно это то, что мне все равно придется катиться в метод, который я пишу сам. Это не совсем то, что я собираюсь, так как он по-прежнему включает часы, минуты и секунды в возвращаемом значении миллисекунды - хотя я мог бы, вероятно, заставить его работать для моих целей.
Я все еще думаю о каждом компоненте как отдельном, хотя, конечно, это не так. Вы можете записать время как миллисекунды с произвольной контрольной даты, или вы можете написать то же самое время, что и year/month/day hours:minutes:seconds.milliseconds
.
Это не для показа. Я знаю, как использовать DateFormat
для создания строк с красивой датой.
Изменить 2: Мой первоначальный вопрос возник из небольшого набора полезных функций, которые я нашел, например:
- Проверка того, представляют ли два
Date
дату-дату в тот же день;
- Проверка того, находится ли дата в пределах диапазона, указанного двумя другими датами, но иногда проверяя включительно, а иногда и нет, в зависимости от компонента времени.
Имеет ли время Joda этот тип функциональности?
Редактировать 3: @Задайте вопрос о моем втором требовании, просто чтобы уточнить: второе требование - результат использования моих дат, чтобы иногда представлять целые дни - где компонент времени не имеет значения в все - и иногда представляют дату-время (то есть IMO, самое точное слово для чего-то, что содержит year/month/day
и hours:minutes:seconds:...
).
Когда Date представляет целый день, его временные части равны нулю (например, компонент времени "Дата" - полночь), но семантика диктует, что проверка диапазона выполняется, включительно, в дату окончания. Поскольку я просто оставляю эту проверку до Date:: before и Date:: after, я должен добавить 1 день до даты окончания - следовательно, специальная оболочка, когда компонент времени дня Date равен нулю.
Надеюсь, что это не сделало вещи менее ясными.
Ответы
Ответ 1
Извлечение временной части дня должно быть вопросом получения оставшегося количества миллисекунд при делении на количество миллисекунд в день.
long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
Date now = Calendar.getInstance().getTime();
long timePortion = now.getTime() % MILLIS_PER_DAY;
В качестве альтернативы рассмотрите использование joda-time, более полнофункциональной библиотеки времени.
Ответ 2
Хорошо, я знаю, что это предсказуемый ответ, но... используйте Joda Time. У этого есть отдельные представления для "даты", "момента", "времени суток" и т.д. Это более богатый API и, как правило, более здравый, чем встроенные классы, IMO.
Если это единственный бит манипуляции с датой/временем, который вам интересен, тогда это может быть чрезмерным... но если вы используете встроенный API даты/времени для чего-либо значимого, я настоятельно рекомендую что вы отодвигаетесь от него до Йоды, как только сможете.
В стороне, вы должны подумать о том, в каком часовом поясе вас интересует. Calendar
имеет связанный часовой пояс, но Date
не (он просто представляет момент во времени, измеренный в миллисекундах от эпоха Unix).
Ответ 3
Чтобы ответить на его часть, доступ к миллисекундному компоненту выполняется следующим образом:
long mill = Calendar.getInstance().getTime();
Я не знаю, что вы хотите сделать со спецификой, но вы можете использовать класс java.text.SimpleDateFormat, если он предназначен для вывода текста.
Ответ 4
Вы можете вызвать функцию getTimeInMillis() объекта Calendar, чтобы получить время в миллисекундах. Вы можете вызвать get (Calendar.MILLISECOND) на объект календаря, чтобы получить миллисекунды секунды. Если вы хотите отобразить время с объекта Date или Calendar, используйте класс DateFormat. Пример: DateFormat.getTimeInstance(). Format (сейчас). Существует также класс SimpleDateFormat, который вы можете использовать.
Ответ 5
Чтобы просто использовать Joda-Time, используйте класс org.joda.time.LocalTime
, как описано в этом вопросе, Joda-Time, Time without date.
Что касается сравнения дат только при эффективном игнорировании времени, в Joda-Time вызовите метод withTimeAtStartOfDay()
на каждом экземпляре DateTime
, чтобы установить идентичное значение времени. Вот пример кода, использующего Joda-Time 2.3, аналогичный тому, что я опубликовал сегодня на другом ответе.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// Joda-Time - The popular alternative to Sun/Oracle notoriously bad date, time, and calendar classes bundled with Java 7 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
// Capture one moment in time.
org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println("Now: " + now);
// Calculate approximately same time yesterday.
org.joda.time.DateTime yesterday = now.minusDays(1);
System.out.println("Yesterday: " + yesterday);
// Compare dates. A DateTime includes time (hence the name).
// So effectively eliminate the time by setting to start of day.
Boolean isTodaySameDateAsYesterday = now.withTimeAtStartOfDay().isEqual(yesterday.withTimeAtStartOfDay());
System.out.println("Is today same date as yesterday: " + isTodaySameDateAsYesterday);
org.joda.time.DateTime halloweenInUnitedStates = new org.joda.time.DateTime(2013, 10, 31, 0, 0);
Boolean isFirstMomentSameDateAsHalloween = now.withTimeAtStartOfDay().isEqual(halloweenInUnitedStates.withTimeAtStartOfDay());
System.out.println("Is now the same date as Halloween in the US: " + isFirstMomentSameDateAsHalloween);
Ответ 6
Если все, о чем вы беспокоитесь, попадает в String для отображения или сохранения, просто создайте SimpleDateFormat, который отображает только временную часть, например новый SimpleDateFormat ( "HH: mm: ss" ). Конечно, дата все еще находится в объекте Date, но вам все равно.
Если вы хотите сделать арифметику на ней, например, взять два объекта Date и найти, сколько секунд друг от друга, они игнорируют часть даты, так что "2009-09-01 11:00:00" минус "1941-12 -07 09:00:00" равно 2 часам, то я думаю, вам нужно использовать решение, подобное Jherico's: получите много времени и возьмите модуль 1 день.
Ответ 7
Почему вы хотите их разделить? Если вы хотите сделать арифметику с временной частью, вы быстро попадете в беду. Если вы выйдете из 11:59 вечера и добавьте минуту, теперь, когда ваше время и день будут раздельными, вы сами напортачили - у вас будет неправильное время и неправильная дата.
Если вы просто хотите их отобразить, то при применении различных простых форматов даты вы получите именно то, что хотите.
Если вы хотите манипулировать датой, я предлагаю вам получить длинные значения и основывать все на этом. В любой момент вы можете сделать это долго и применить формат, чтобы отображать минуты/часы/секунды.
Но я немного обеспокоен концепцией манипулирования днем и временем по отдельности, похоже, открывая червяки. (Не говоря уже о проблемах с часовым поясом!).
Я уверен, что именно поэтому у Java нет простого способа сделать это.
Ответ 8
Найдите ниже решение, которое использует время Joda и поддерживает часовые пояса.
Таким образом, вы получите дату и время (в currentDate
и currentTime
) в текущем настроенном часовом поясе в JVM.
Обратите внимание, что Joda Time не поддерживает прыжки секунд. Таким образом, вы можете быть на 26 или 27 секунд от истинного значения. Вероятно, это будет разрешено только в ближайшие 50 лет, когда накопленная ошибка будет ближе к 1 минуте, и люди начнут заботиться об этом.
Смотрите также: https://en.wikipedia.org/wiki/Leap_second
/**
* This class splits the current date/time (now!) and an informed date/time into their components:
* <lu>
* <li>schedulable: if the informed date/time is in the present (now!) or in future.</li>
* <li>informedDate: the date (only) part of the informed date/time</li>
* <li>informedTime: the time (only) part of the informed date/time</li>
* <li>currentDate: the date (only) part of the current date/time (now!)</li>
* <li>currentTime: the time (only) part of the current date/time (now!)</li>
* </lu>
*/
public class ScheduleDateTime {
public final boolean schedulable;
public final long millis;
public final java.util.Date informedDate;
public final java.util.Date informedTime;
public final java.util.Date currentDate;
public final java.util.Date currentTime;
public ScheduleDateTime(long millis) {
final long now = System.currentTimeMillis();
this.schedulable = (millis > -1L) && (millis >= now);
final TimeZoneUtils tz = new TimeZoneUtils();
final java.util.Date dmillis = new java.util.Date( (millis > -1L) ? millis : now );
final java.time.ZonedDateTime zdtmillis = java.time.ZonedDateTime.ofInstant(dmillis.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdmillis = java.util.Date.from(tz.tzdate(zdtmillis));
final java.util.Date ztmillis = new java.util.Date(tz.tztime(zdtmillis));
final java.util.Date dnow = new java.util.Date(now);
final java.time.ZonedDateTime zdtnow = java.time.ZonedDateTime.ofInstant(dnow.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdnow = java.util.Date.from(tz.tzdate(zdtnow));
final java.util.Date ztnow = new java.util.Date(tz.tztime(zdtnow));
this.millis = millis;
this.informedDate = zdmillis;
this.informedTime = ztmillis;
this.currentDate = zdnow;
this.currentTime = ztnow;
}
}
public class TimeZoneUtils {
public java.time.Instant tzdate() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tzdate(zdtime);
}
public java.time.Instant tzdate(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final java.time.Instant instant = zddate.toInstant();
return instant;
}
public long tztime() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tztime(zdtime);
}
public long tztime(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final long millis = zddate.until(zdtime, java.time.temporal.ChronoUnit.MILLIS);
return millis;
}
}
Ответ 9
TL;DR
LocalTime lt = myUtilDate.toInstant().atZone( ZoneId.of( "America/Montreal" ) ).toLocalTime() ;
Избегать старых классов времени
Используются старые устаревшие классы времени. Они хлопотны и запутываются; избежать их.
Вместо этого используйте классы java.time. Они вытесняют старые классы, а также библиотеку Joda-Time.
Преобразовать
Преобразуйте java.util.Date
в Instant
.
Instant
класс представляет момент на временной шкале в UTC с разрешением наносекунды.
Instant instant = myUtilDate.toInstant();
Часовой пояс
Применить часовой пояс. Часовой пояс имеет решающее значение. В любой момент времени по всему миру меняется зона. Например, через несколько минут после полуночи в Париже Франция - новый день, а также "вчера" в Монреале Квебек.
Примените ZoneId
, чтобы получить объект ZonedDateTime
.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Local…
типы
Класс LocalDate
представляет значение даты только без времени и без часового пояса. Аналогично, LocalTime
представляет собой время суток без даты и без часового пояса. Вы можете думать об этом как о двух компонентах, которые вместе с ZoneId
составляют ZonedDateTime
. Вы можете извлечь их из ZonedDateTime
.
LocalDate ld = zdt.toLocalDate();
LocalTime lt = zdt.toLocalTime();
Строки
Если ваша цель - просто генерировать строки для представления пользователю, нет необходимости в типах Local…
. Вместо этого используйте DateTimeFormatter
, чтобы генерировать строки, представляющие только часть даты или часть времени. Этот класс достаточно умен, чтобы автоматически локализовать при создании строки.
Укажите Locale
, чтобы определить (а) человеческий язык, используемый для перевода имени дня, имени месяца и т. и (b) культурные нормы для решения таких вопросов, как сокращение, капитализация, пунктуация и т.д.
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter fDate = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale );
String outputDate = zdt.format( fDate );
DateTimeFormatter fTime = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ).withLocale( locale );
String outputTime = zdt.format( fTime );
О java.time
Структура java.time встроена в Java 8 и более поздних версий. Эти классы вытесняют старые неприятные классы времени, такие как java.util.Date
, .Calendar
и java.text.SimpleDateFormat
.
Проект Joda-Time, теперь режим обслуживания, советует перейти на java.time.
Чтобы узнать больше, см. Учебник Oracle. И поиск Qaru для многих примеров и объяснений.
Большая часть функций java.time возвращается на Java 6 и 7 в ThreeTen-Backport и далее адаптируется к Android в ThreeTenABP (см. Как использовать...).
Проект ThreeTen-Extra расширяет java.time с помощью дополнительных классов. Этот проект является доказательством возможных будущих дополнений к java.time.