Проблема сохранения дневного света с календарем Java

Это касается календаря Java и эффектов, с которыми мы столкнулись после сегодняшнего изменения дневного света в Торонто.

Ниже приведен код

    Date date = new Date(); //Sun Mar 11 00:00:00 EST 2018
    Integer time = 349;

    Calendar scheduleDateCal = Calendar.getInstance();
    scheduleDateCal.setTime(date);

    scheduleDateCal.set(Calendar.MINUTE, 0);
    scheduleDateCal.set(Calendar.HOUR_OF_DAY, 0);
    String strSchAdminTime = String.valueOf(time);
    Integer schAdminMinute = time;

    if (strSchAdminTime.length() >= 2) {
        schAdminMinute = Integer.valueOf(strSchAdminTime.substring(strSchAdminTime.length()-2));
    } 
    if(time>60){
        Integer schAdminHour = Integer.valueOf(strSchAdminTime.substring(0,strSchAdminTime.length()-2));
        scheduleDateCal.add(Calendar.HOUR_OF_DAY, schAdminHour);
    }else{
        scheduleDateCal.add(Calendar.HOUR_OF_DAY, 0);
    }
    scheduleDateCal.add(Calendar.MINUTE, schAdminMinute);

    System.out.println(scheduleDateCal.getTime());

Я знаю, что этот код не соответствует лучшим практикам, но мне нужно сохранить его в текущем выпуске. Здесь используется целое число для представления временной части, а позже есть логика для извлечения из нее часов и минут.

Когда я следовал логике, часовая часть равна 3. Затем есть логика, чтобы добавить это время в объект Calendar со значением «Sun Mar 11 00:00:00 EST 2018» с помощью приведенного ниже утверждения.

scheduleDateCal.add(Calendar.HOUR_OF_DAY, schAdminHour);

Теоретически после этого расчета объект календаря должен иметь значение «Sun Mar 11 03:00:00 EDT 2018». Однако он возвращает «Sun Mar 11 04:00:00 EDT 2018». Я знаю, что с сегодняшнего дня время будет идти на час вперед с переходом на летнее время. Может ли кто-нибудь помочь мне понять это

Цените помощь.


person keth    schedule 11.03.2018    source источник
comment
Вы правы насчет лучших практик. Для самого раннего конвенционного будущего выпуска я рекомендую вам перейти на использование java.time, современной даты Java и time API. Calendar и Date давно устарели, и работать с современным API намного приятнее.   -  person Ole V.V.    schedule 11.03.2018
comment
К вашему сведению, неприятные старые классы даты и времени, такие как java.util.Date , java.util.Calendar и java.text.SimpleDateFormat теперь являются устаревшими, замененными java.time классы, встроенные в Java 8 и Java 9 . См. Руководство от Oracle.   -  person Basil Bourque    schedule 22.03.2018


Ответы (2)


В 00:00:00 сегодня (воскресенье, 11 марта 2018 г.) летнее время (DST) еще не действовало, поэтому время было правильно отображено как Sun 11 марта 00:00:00 EST 2018 (EST для восточного стандартного времени). Date.toString выбирает между EST и EDT на основе времени, содержащегося в объекте Date (а не на основе времени вызова метода toString). Когда вы добавляете 3 часа к этому времени, вы пересекаете время на отметке 2, когда часы были переведены вперед на 3. Итак, через 3 часа после вашего начального времени время будет 04:00:00 EDT (EDT для восточного летнего времени).

PS Современный код

PS В случае, если вам или кому-то еще интересно, вот современная - и более простая, и более короткая - версия вашего кода. Чтобы установить время на 03:49:

    int time = 349;
    ZoneId zone = ZoneId.of("America/Toronto");
    ZonedDateTime scheduledDateTime = LocalDate.now(zone)
            .atTime(time / 100, time % 100)
            .atZone(zone);
    System.out.println(scheduledDateTime);

Сегодня это напечатано

2018-03-11T03: 49-04: 00 [Америка / Торонто]

Еще лучше, конечно, если вы можете полностью избавиться от представления 03:49 как целого числа 349. Чтобы использовать настройку часового пояса JVM, вы можете установить zone на ZoneId.systemDefault(). Это ненадежно, потому что этот параметр может быть изменен в любое время другими частями вашей программы или другими программами, работающими в той же самой JVM.

Чтобы установить время на 3 часа 49 минут после полуночи (что с переходом на летнее время не одно и то же, как вы видели):

    ZonedDateTime scheduledDateTime = LocalDate.now(zone)
            .atStartOfDay(zone)
            .plusHours(time / 100)
            .plusMinutes(time % 100);

На этот раз я получил

2018-03-11T04: 49-04: 00 [Америка / Торонто]

person Ole V.V.    schedule 11.03.2018
comment
спасибо @Ole V.V за комментарий. Пока я отлаживал код, я обнаружил, что объект календаря изначально был EDT, но как только он выполняет scheduleDateCal.set (Calendar.HOUR_OF_DAY, 0); он изменился на эст - person keth; 11.03.2018
comment
Звучит правильно. Начальным значением объекта Calendar является текущее время, поэтому, если вы запустите код после 3, он будет в EST. - person Ole V.V.; 11.03.2018

EST - -5, EDT - -4, поэтому вы получаете 1 час при вызове add (). Вы можете использовать scheduleDateCal.set(Calendar.HOUR_OF_DAY, schAdminHour) и scheduleDateCal.set(Calendar.MINUTE, schAdminMinute), если вам нужен результат в другом часовом поясе.

person alexq    schedule 11.03.2018
comment
Спасибо за ответ. Вы хоть представляете, почему Date date = new Date (); повторный запуск в EST (вс, 11 марта, 00:00:00 EST 2018), даже мой часовой пояс изменился на EDT - person keth; 11.03.2018
comment
Ваша версия Java новая? База данных часовых поясов, включенная в среду выполнения Java, нуждается в обновлении иногда, когда местные власти изменяют правила начала / окончания летнего периода. Вы можете исправить свою Java с помощью инструмента обновления часовых поясов, см. Ссылку: oracle .com / us / technologies / java / tzupdater-readme-136440.html. - person alexq; 11.03.2018