Путаница с классом Date Java и функцией getTime () - PullRequest
0 голосов
/ 15 апреля 2020

Я новичок в классе Java. Когда я пытаюсь использовать функцию getTime () для вычисления разницы во времени, возникают проблемы. Например, ниже приведен код.


            Date date = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

            task = opt.get();
            task.setEndDate(dateFormat.format(date));

            Date startDate = null;
            try {
                startDate = dateFormat.parse(task.getStartDate());
            } catch (ParseException e) {
                System.out.println("date parsing error...");
                startDate = date;
            }

            System.out.printf("Start date is: %s", task.getStartDate());
            System.out.printf("Start date is: %d", startDate.getTime());
            System.out.printf("End date is: %s", task.getEndDate());
            System.out.printf("End date is: %d", date.getTime());

            long diff = date.getTime() - startDate.getTime() - 43200000;
            System.out.printf("Time difference is: %d", diff);
            int secNum = (int)(diff / 1000);

            String timeCost = String.valueOf(secNum);
            System.out.println("Time cost(sec) is:");
            System.out.println(timeCost);
            task.setTimeCost(timeCost);

Выходные данные:

Start date is: 2020-04-15 01:46:17
Start date is: 1586929577000
End date is: 2020-04-15 01:46:35
End date is: 1586972795461
Time difference is: 18461
Time cost(sec) is:18

Как вы могли заметить, между вычисленной разницей и вычисленной разницей в 12 часов (43200000 мс) реальная разница через "date.getTime () - startDate.getTime ()".

Я не знаю, что происходит. У кого-нибудь есть идея и поправьте меня?

Ответы [ 3 ]

2 голосов
/ 15 апреля 2020

Кажется, вы сохраняете дату / время в виде строки в вашем task объекте и конвертируете между Date и String, используя формат "yyyy-MM-dd hh:mm:ss". Я считаю, что строчные буквы h означают, что вы используете 12-часовые часы, но вы не включили индикатор AM / PM в строку формата.

Я предполагаю, что вы запустили код на 1: 46 пополудни, чтобы произвести пример вывода.

В качестве даты начала хранится "2020-04-15 01:46:17". Когда вы конвертируете это обратно в дату, программа форматирования не знает, будет ли это время AM или PM. Я предполагаю, что по умолчанию используется AM.

Однако объект Date знает, что он был инициализирован с временем PM. Поэтому, когда вы вычитаете два, вы получаете разницу в 12 часов, потому что она вычитает 1:46:17 из 13:46:35.

Простая рекомендация - добавить AM / PM указатель на формат даты или используйте 24-часовые часы (в верхнем регистре H в строке формата).

Еще лучше рекомендовать сохранять даты как даты, а не как строки ! Преобразуйте их в строки, если хотите их отобразить.

1 голос
/ 16 апреля 2020

java .time

Я новичок в классе дат Java.

Стоп! Резервное копирование, перемотка.

Оба java.util.Date и java.sql.Date классы ужасны , глубоко порочны и довольно разочаровывают. Никогда не используйте эти классы.

Эти классы были поставлены в самых ранних версиях Java. Смененные годы go современными java .time классами, определенными в JSR 310 .


Date date = new Date();

Чтобы зафиксировать текущий момент в UT C, используйте Instant.now. Использует разрешение, меньшее, чем миллисекунды, используемые в классе java.util.Date, который он заменил.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

task.setEndDate(dateFormat.format(date));

Ваш класс Task должен удерживайте объект java .time вместо простой строки.

class Task {
    Instant start , stop ;
    …
}

Используйте умные объекты, а не тупые строки в вашей кодовой базе Java. Это обеспечивает допустимые значения , обеспечивает безопасность типов и делает ваш код более самодокументирующимся .

Если ваш Task например, при бронировании встреч в будущем, когда вам нужно определенное время суток, независимо от изменений смещения, используемых вашим часовым поясом, затем используйте LocalDateTime. Этот тип представляет только дату и время суток, но не имеет понятия о часовом поясе или смещении.

LocalDate ld = LocalDate.of( 2020 , Month.APRIL , 15 ) ;
Localtime lt = LocalTime.of( 15 , 30 ) ;
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;

При создании календаря, в котором вам нужна указанная точка c на временной шкале, затем примените соответствующий часовой пояс.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

На карту поставлен вопрос о том, что политики во всем мире проявляют склонность к изменению смещения, используемого часовым поясом (ами) своей юрисдикции. Политики делают это с удивительной частотой. И они сделали это практически без предупреждения.

При текстовом обмене значениями даты и времени с другими системами используйте форматы ISO 8601 . Эти форматы используются по умолчанию в java .time при разборе / генерации текста. А для представления пользователям создайте автоматически локализованные строки, используя DateTimeFormatter.


new SimpleDateFormat ("гггг-мм-дд чч: мм: сс")

Этот формат неверен, если вы пытаетесь записать моменты, указав c точек на временной шкале. Вы должны включить индикацию часовой пояс и / или смещение от UT C для отслеживания момента.

Для моментов используйте форматы ISO 8601 упомянутый выше. Используется по умолчанию, поэтому нет необходимости указывать шаблон форматирования.

String input = "2020-01-23T01:23:45.123456789Z" ;
Instant instant = Instant.parse( input ) ;

Настройте с UT C на время в настенных часах, используемое людьми определенного региона (часового пояса).

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Создание локализованного текста.

Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;

См. Этот код, запущенный в режиме реального времени на IdeOne.com .

zdt.toString (): 2020-01-22T20: 23: 45.123456789-05: 00 [Америка / Монреаль]

выход: mercredi 22 января 2020 à 20 ч 23 мин 45 с heure normale de l'Est


long diff = date.getTime() - startDate.getTime() - 43200000;

Нет необходимости делать математику самостоятельно. У нас есть класс для этого: Duration.

Duration d = Duration.between( start , stop ) ;

Если вам нужен отсчет целых секунд за весь промежуток времени, позвоните по номеру Duration::toSeconds.

long seconds = d.toSeconds() ;  // Entire duration in terms of whole seconds.

О java .time

Рамка java .time встроенный в Java 8 и позже. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

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

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

Вы можете обмениваться java .time объектами непосредственно с вашей базой данных. Используйте драйвер JDB C , совместимый с JDB C 4. 2 или позже. Нет необходимости в строках, нет необходимости в java.sql.* классах. Поддержка Hibernate 5 и JPA 2.2 java .time .

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

  • Java SE 8 , Java SE 9 , Java SE 10 , Java SE 11 и более поздних версий - часть стандартного API Java со связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большинство функций java .time перенесено на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java .time .
    • Для более ранних Android (<26) <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP проект адаптируется ThreeTen-Backport (упомянуто выше). См. Как использовать ThreeTenABP… .

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

1 голос
/ 15 апреля 2020

Вы используете hh, который представляет собой 12-часовой формат, поэтому 20:00 становится 08:00. Вы должны использовать HH, который является 24-часовым форматом. Ниже показано различие.

        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        Date date = new Date(1586973600000L);
        System.out.println(date);

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String fd1 = df.format(date);
        System.out.println(fd1);
        System.out.println(df.parse(fd1));

        df.applyPattern("yyyy-MM-dd HH:mm:ss");
        String fd2 = df.format(date);
        System.out.println(fd2);
        System.out.println(df.parse(fd2));

Кроме того, java.util.Date является старым, глючным и его обычно избегают в течение некоторого времени. Вы можете вместо этого переключиться на java.time.

...