Получение компонента времени 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.