Как ввести дату с клавиатуры java
В этой статье мы рассмотрим новые API Java 8 для определения даты и времени, а также насколько проще создавать и манипулировать датами и временем.
1. Обзор
Java 8 представила новые API для Даты и времени для устранения недостатков более старых java.util.Дата и java.util.Календарь .
В рамках этой статьи давайте начнем с проблем в существующих Date и Calendar API и обсудим, как новые API Java 8 Date и Time решают их.
Мы также рассмотрим некоторые основные классы нового проекта Java 8, которые являются частью пакета java.time , например LocalDate , LocalDateTime, LocalDateTime, ZonedDateTime, Period, Duration и их поддерживаемые API.
Дальнейшее чтение:
Работа с параметрами даты весной
Проверьте, является ли строка Допустимой датой в Java
2. Проблемы с существующими API-интерфейсами даты и времени
- Потокобезопасность – Классы Дата и Календарь не являются потокобезопасными, оставляя разработчикам решать головную боль, связанную с трудными проблемами отладки параллелизма и написанием дополнительного кода для обработки потокобезопасности. Напротив, новые API Date и Time , представленные в Java 8, являются неизменяемыми и потокобезопасными, что избавляет разработчиков от головной боли параллелизма.
- Дизайн API и простота понимания – API Дата и Календарь плохо разработаны с неадекватными методами для выполнения повседневных операций. Новый API Date/Time является изоцентрическим и следует согласованным моделям домена для даты, времени, продолжительности и периодов. Существует большое разнообразие полезных методов, которые поддерживают самые распространенные операции.
- ZonedDateиTime – Разработчикам пришлось написать дополнительную логику для обработки логики часового пояса со старыми API, в то время как с новыми API обработка часового пояса может выполняться с помощью Local и ZonedDate /| Time API.
3. Использование LocalDate, LocalTime и LocalDateTime
Наиболее часто используемыми классами являются LocalDate , LocalTime и LocalDateTime . Как следует из их названий, они представляют локальную дату/время из контекста наблюдателя.
Эти классы в основном используются, когда часовой пояс не требуется явно указывать в контексте. В рамках этого раздела мы рассмотрим наиболее часто используемые API.
3.1. Работа С LocalDate
Локальная дата представляет дату в формате ISO (гггг-ММ-дд) без времени .
Его можно использовать для хранения дат, таких как дни рождения и дни выплаты жалованья.
Экземпляр текущей даты может быть создан из системных часов, как показано ниже:
Local Date предоставляет различные служебные методы для получения разнообразной информации. Давайте быстро взглянем на некоторые из этих методов API.
Следующий фрагмент кода получает текущую локальную дату и добавляет один день:
В этом примере получается текущая дата и вычитается один месяц. Обратите внимание, как он принимает перечисление в качестве единицы времени:
Мы можем проверить, происходит ли дата в високосный год. В этом примере мы проверяем, является ли текущая дата високосным годом:
Связь одной даты с другой может быть определена до или после другой даты:
Границы дат могут быть получены с заданной даты. В следующих двух примерах мы получаем LocalDateTime , представляющий начало дня (2016-06-12T00:00) данной даты, и LocalDate , представляющий начало месяца (2016-06-01) соответственно:
Теперь давайте посмотрим, как мы работаем с местным временем.
3.2. Работа С Местным Временем
Местное время представляет время без даты .
Экземпляр текущего Местного времени может быть создан из системных часов, как показано ниже:
В приведенном ниже примере кода , мы создаем Местное время , представляющее 06:30 утра, путем анализа строкового представления:
Доступны различные методы получения, которые можно использовать для получения определенных единиц времени, таких как час, минута и сек, как показано ниже:
Мы также можем проверить, является ли определенное время до или после другого определенного времени. Приведенный ниже пример кода сравнивает два Местное время , для которых результат будет истинным:
Максимальное, минимальное и полуденное время суток можно получить с помощью констант в классе LocalTime . Это очень полезно при выполнении запросов к базе данных для поиска записей в течение заданного промежутка времени. Например, приведенный ниже код представляет 23:59:59.99:
Теперь давайте погрузимся в LocalDateTime .
3.3. Работа С LocalDateTime
LocalDateTime используется для представления комбинации даты и времени .
Это наиболее часто используемый класс, когда нам нужна комбинация даты и времени. Класс предлагает множество API, и мы рассмотрим некоторые из наиболее часто используемых.
Экземпляр LocalDateTime может быть получен из системных часов, аналогичных LocalDate и LocalTime:
Методы геттера доступны для извлечения определенных единиц измерения, аналогичных классам даты и времени. Учитывая приведенный выше экземпляр LocalDateTime , приведенный ниже пример кода вернет месяц февраль:
4. Использование API ZonedDateTime
В этом фрагменте кода мы создаем Зону для Парижа:
Набор всех идентификаторов зон можно получить следующим образом:
LocalDateTime может быть преобразован в определенную зону:
Метод ZonedDateTime предоставляет метод parse для получения конкретной даты часового пояса:
Экземпляр OffsetDateTime можно создать, как показано ниже, с помощью Zone Offset . Здесь мы создаем LocalDateTime , представляющий 6:30 утра 20 февраля 2015 года:
Затем мы добавим два часа к этому времени, создав смещение зоны и установив для экземпляра LocalDateTime :
Теперь у нас есть LocalDateTime 2015-02-20 06:30 +02:00. Теперь давайте перейдем к тому, как изменить значения даты и времени с помощью классов Period и Duration .
5. Использование периода и продолжительности
Класс Period представляет количество времени в годах, месяцах и днях, а класс Duration представляет количество времени в секундах и наносекундах.
5.1. Работа С Периодом
Класс Period широко используется для изменения значений заданной даты или для получения разницы между двумя датами:
Датой можно управлять с помощью Периода , как показано в следующем фрагменте кода:
Класс Period имеет различные методы получения, такие как getyear, getmonth и getday для получения значений из объекта Period . Приведенный ниже пример кода возвращает int значение 5, поскольку мы пытаемся получить разницу в днях :
Период между двумя датами может быть получен в определенной единице, такой как дни, месяц или годы, с помощью ChronoUnit.between:
Этот пример кода возвращает пять дней. Давайте продолжим, взглянув на класс Duration .
5.2. Работа С Длительностью
Подобно Period, класс Duration используется для работы с Time. В следующем коде мы создаем Местное время 6:30 утра, а затем добавляем продолжительность 30 секунд, чтобы сделать Местное время 06:30:30 утра:
Длительность между двумя моментами может быть получена либо как Длительность , либо как определенная единица измерения. В первом фрагменте кода мы используем метод between() класса Duration , чтобы найти разницу во времени между final Time и initialTime и вернуть разницу в секундах:
Во втором примере мы используем метод between() класса ChronoUnit для выполнения той же операции:
Теперь мы рассмотрим, как преобразовать существующую Дату и Календарь в новую Дату Время.
6. Совместимость с датой и календарем
Java 8 добавила их в метод Instant () , который помогает преобразовать существующие Данные и Календарь экземпляр в новый API даты и времени, как показано в следующем фрагменте кода:
LocalDateTime может быть построен из секунд эпохи, как показано ниже. Результатом приведенного ниже кода будет LocalDateTime , представляющий 2016-06-13T11:34:50:
Теперь перейдем к Дате и времени форматированию.
7. Форматирование даты и времени
Java 8 предоставляет API для удобного форматирования Даты и времени :
Приведенный ниже код передает формат даты ISO для форматирования локальной даты. Результат будет 2015-01-25:
DateTimeFormatter предоставляет различные стандартные параметры форматирования. Пользовательские шаблоны также могут быть предоставлены для метода форматирования, как показано ниже, который вернет Локальную дату как 2015/01/25:
Мы можем передать стиль форматирования как SHORT , LONG или MEDIUM как часть опции форматирования. Приведенный ниже пример кода даст вывод, представляющий LocalDateTime в 25-Jan-2015, 06:30:00:
Давайте рассмотрим альтернативы, доступные для Java 8 Core Date |/Time |/API.
8. Backport и альтернативные варианты
8.1. Использование проектной информации
Для организаций, которые находятся на пути перехода на Java 8 с Java 7 или Java 6 и хотят использовать API даты и времени, project threeten предоставляет возможность обратного порта. Разработчики могут использовать классы, доступные в этом проекте, для достижения той же функциональности, что и в новом Java 8 Date и Time API, и как только они перейдут на Java 8, пакеты могут быть переключены. Артефакт для проекта можно найти в центральном репозитории maven :
8.2. Библиотека Joda-Time
Другой альтернативой для Java 8 Date и Time library является Joda-Time library. На самом деле Java 8 Date Time API был совместно разработан автором библиотеки Joda-Time (Стивен Коулборн) и Oracle. Эта библиотека предоставляет практически все возможности, которые поддерживаются в Java 8 Date Time project. Артефакт можно найти в maven central , включив в свой проект приведенную ниже зависимость pom:
9. Заключение
Java 8 предоставляет богатый набор API с согласованным дизайном API для облегчения разработки.
Примеры кода для приведенной выше статьи можно найти в репозитории Java 8 Date/Time git.
При работе с приложениями или сайтами, пользователям необходимо вводить свои данные: почту, пароль, день рождения и так далее. В Java применяются несколько способов ввода данных с клавиатуры: c помощью метода readLine() класса BufferedReader или метода nextLine() класса Scanner. Разберем подробнее, как работают эти методы.
Метод readLine()
BufferedReader readLine() применяется для чтения одной строки текста, который пользователь ввел с консоли. Конец строки в коде может быть указан как Enter, так и \n , \r или EOF — end of file.
BufferedReader readLIne() работает только со строками в коде. А метод Scanner nextLine() считывает и другие типы данных, например, int, long, double, float.
BufferedReader работает немного быстрее по сравнению со Scanner, потому что nextLine() анализирует данные, а readLine() просто считывает последовательность символов.
Так работает readLine():
И на экран, соответственно, выводится:
Метод nextLine()
NextLine() в Java применяется для класса Scanner. Этот метод так же, как и readLine(), нужен для получения и чтения данных, написанных пользователем. Чтобы применить nextLine(), в коде нужно прописать объект Scanner.
Этот метод читает и воспроизводит данные до конца строки. Другими словами, он может считывать информацию до тех пор, пока не начнется новая строка или старая не будет разорвана с помощью \n или Enter.
Вот как nextLine() работает в Java:
Что пишет пользователь:
Что показывает программа:
Метод nextLine работает с данными только одной строки, поэтому остальное стихотворение теряется из-за разрыва между предложениями и перехода на новую строчку.
Чтобы показать стих полностью, нужно написать следующий код:
Классы-обертки в Java
Класс-обертка — это класс, объект которого содержит примитивные типы данных. Когда мы создаем объект для класса-обертки, он содержит поле, в котором мы можем хранить примитивные типы данных.
Как работают классы-обертки:
- Они преобразуют примитивные типы данных в объекты. Это необходимо, когда мы хотим изменить аргументы, передаваемые через метод (поскольку примитивные типы передаются только через value).
- В пакете java.util классы могут обрабатывать только объекты, и в этом случае помогут обертки.
- Чтобы работать в коллекциях ArrayList и Vector, потребуются объекты, а не примитивные типы.
- Классы-обертки необходимы для поддержки синхронизации в режиме многопоточности.
В коде процесс создания классов-оберток выглядят так:
А если нужно совершить обратный процесс и преобразовать класс-обертку в примитивный тип, то придется совершить unboxing или распаковку данных:
Highload нужны авторы технических текстов. Вы наш человек, если разбираетесь в разработке, знаете языки программирования и умеете просто писать о сложном!
Откликнуться на вакансию можно здесь .
В Java используются два основных способа ввода данных с клавиатуры:
С помощью метода readLine() объекта, порожденного от класса BufferdReader из пакета java.io.
С помощью nextLine() и других методов объекта, созданного от класса Scanner из пакета java.util.
Однако в обоих случаях изначально используется System.in – объект класса InputStream, присвоенный переменной in, находящейся в классе System пакета java.lang. Данный объект выполняет функцию стандартного потока ввода, т. е. ввода с клавиатуры. (В то время как System.out – стандартный поток вывода.)
В Java объект System.in обеспечивает низкоуровневый ввод, при котором методом read() считываются байты. Например, если ввести "ab" и нажать Enter, будет прочитано три байта. В десятичном представлении значение первого байта будет соответствовать символу "a" по таблице символов, второго – символу "b", третьего – символу перехода на новую строку.
Если же ввести букву национального алфавита, которая не может кодироваться одним байтом, то каждый ее составляющий байт будет прочитан по отдельности.
Для преобразования байтов в символы, а затем в строки полученное от System.in передают в конструкторы классов-оберток. Обертки используют функционал переданного им объекта, но дополняют его своим.
Первая обертка – класс InputStreamReader, который преобразует набор байтов в символ. Класс BufferedReader буферизует ввод, обеспечивая считывание из потока ввода (клавиатура это или файл – не важно) целых строк, что делает процесс более быстрым.
Выражение BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); есть сокращенная запись от:
В случае Scanner дело обстоит попроще, так как класс может больше:
У сканера есть методы, проверяющие тип вводимых данных (hasNextInt() и т. п.). Несмотря на удобство Scanner, если надо просто считывать строки без их анализа, предпочитают использовать BufferedReader, так как он работает быстрее. В остальном выбор зависит от специфики задачи.
Класс SimpleDateFormat является подклассом класса DateFormat и позволяет определять собственные шаблоны форматирования для отображения даты и времени.
На странице рассмотрены следующие классы :
- форматирование SimpleDateFormat
- календарь Calendar
- григорианский календарь GregorianCalendar
- временная зона TimeZone
Класс Date
Класс Date хранит время в миллисекундах начиная с 1 января 1970 года. Данный класс имеет конструктор по умолчанию, который возвращает текущее время. Кроме этого можно создать объект Date используя конструктор, который принимает количество миллисекунд начиная с 1 января 1970 года. Для получения этого внутреннего времени используется метод getTime(). Кроме этого уже после создания экземпляра класса можно изменить время с помощью setTime(long date).
Конструкторы класса Date :
Первый конструктор без параметров инициализирует объект текущей датой и временем. Во втором конструкторе можно указать количество миллисекунд, прошедших с полуночи 1 января 1970 года.
Методы класса Date:
- boolean after(Date date) - если объект содержит более позднюю дату, чем указано в параметре date, то возвращается true;
- boolean before(Date date) - если объект содержит более раннюю дату, чем указано в параметре date, то возвращается true;
- int compareTo(Date date) - сравнивает даты. Возвращает 0, если совпадают, отрицательное значение - если вызывающая дата более ранняя, положительное значение - если вызывающая дата более поздняя, чем в параметре;
- boolean equals(Object object) - если даты совпадают, то возвращается true;
- long getTime() - возвращает количество миллисекунд, прошедших с полуночи 1 января 1970 года;
- void setTime(long milliseconds) - устанавливает время и дату в виде числа миллисекунд, прошедших с полночи 1 января 1970 года.
Простой пример использования Date для вывода даты в консоль.
С помощью метода getTime() можно отобразить количество миллисекунд, прошедших с 1 января 1970 года.
Класс SimpleDateFormat
Для того, чтобы отображать дату и время в удобном формате можно использовать класс SimpleDataFormat :
При создании шаблона представления даты SimpleDateFormat использовались следующие параметры :
- dd — означает день;
- MM — месяц;
- yyyy — год;
- hh — часы;
- mm — минуты;
В качестве разделитель можно использовать любой текст.
Класс SimpleDateFormat является подклассом класса DateFormat и позволяет определять собственные шаблоны форматирования для отображения даты и времени.
Символы форматирования строки
- A - AM или PM
- d - день месяца (1-31)
- D - день в году (1-366)
- H - часы в формате AM/PM (1-12)
- K - часы в формате суток (1-24)
- M - минуты (0-59)
- S - секунды (0-59)
- W - неделя в году (1-53)
- y - год
- z - часовой пояс
Количество повторений символа определяет способ представления даты. Например, можно указать hh:mm:ss, а можно h:m:s. В первом случае при необходимости для чисел 0..9 будет отображаться ноль перед цифрой.
Класс Calendar
В документации представлено множество методов для получения или установки отдельных компонентов времени и даты, например, getMinutes()/setMinutes() и др. Все они являются устаревшими и вместо них следует использовать класс Calendar.
Абстрактный класс Calendar позволяет работать с датой в рамках календаря, т.е он умеет прибавлять день, при этом учитывать високосные год и прочее, а также позволяет преобразовать время в миллисекундах в более удобном виде - год, месяц, день, часы, минуты, секунды. Единственной реализацией Calendar является класс GregorianCalendar, также как и у даты конструктор по умолчанию возвращает календарь на текущий день, но можно задать его явно указав все параметры :
Пример использования классов Calendar и GregorianCalendar
Поля класса Calendar
- Переменная типа boolean с именем areFieldsSet указывает, были ли установлены компоненты времени.
- Переменная fields - это массив целочисленных значений, содержащий компоненты времени.
- Переменная isSet - массив типа boolean, указывающий, был ли установлен специфический компонент времени.
- Переменная time (тип long) содержит текущее время объекта.
- Переменная isTimeSet (тип boolean) указывает, что было установлено текущее время.
Методы класса Calendar
Наименование | Описание |
---|---|
abstract void add(int field, int value) | добавляет value к компоненту времени или даты, указанному в параметре field (например, Calendar.HOUR). Чтобы отнять, используйте отрицательное значение. |
boolean after(Object calendar) | возвращает значение true, если вызывающий объект класса Calendar содержит более позднюю дату, чем calendar. |
boolean before(Object calendar) | возвращает значение true, если вызывающий объект класса Calendar содержит более раннюю дату, чем calendar. |
final void clear() | обнуляет все компоненты времени в вызывающем объекте. |
final void clear(int field) | обнуляет компонент, указанный в параметре field |
int get(int field) | возвращает значение одного компонента, например, Calendar.MINUTE |
synchronized static Locale[] getAvailableLocales() | возвращает массив объектов класса Locale, содержащий региональные данные |
synchronized static Calendar getInstance() | возвращает объект класса Calendar для региональных данных и часового пояса по умолчанию. Есть и другие перегруженные версии. |
final Date getTime() | возвращает объекта класса Date, содержащий время, эквивалентное вызывающему объекту. |
TimeZone getTimeZone() | возвращает часовой пояс |
final boolean isSet(int field) | возвращает значение true, если указанный компонент времени указан. |
void set(int field, int value) | устанавливает компоненты даты или времени. Есть перегруженные версии. |
final void setTime(Date date) | устанавливает различные компоненты даты и времени через объект класса Date. |
void setTimeZone(TimeZone timezone) | устанавливает часовой пояс через объект класса TimeZone. |
Календарь достаточно мощный класс, который позволяет получать названия месяцев и дней недели, увеличивать или уменьшать различные параметры текущей даты, а также получать их. Для удобства работы с ним нужно просто разобраться с типами данных, с которыми он работает:
- DAY_OF_YEAR — день года (0- 365);
- DAY_OF_MONTH — день месяца( какой по счету день в месяце 0 — 31);
- WEEK_OF_MONTH — неделя месяца;
- WEEK_OF_YEAR — неделя в году;
- MONTH — номер месяца;
- Year — номер года;
- Calendar.ERA — эра.
Пример Calendar, GregorianCalendar
Класс GregorianCalendar
Класс GregorianCalendar является подклассом Calendar, который представляет обычный Григорианский календарь. Метод getInstance() класса Calendar обычно возвращает объект класса GregorianCalendar, инициированный текущей датой и временем согласно региональным настройкам.
У класса есть два поля AD и BC - до нашей эры и наша эра.
Кроме стандартных методов, которые есть в классе Calendar, у GregorianCalendar есть метод isLeapYear() для проверки високосного года:
Если год високосный, то возвращается true.
Отсчёт месяцев идёт от нуля, поэтому декабрь будет одиннадцатым месяцем. Чтобы не путаться с такими случаями, проще использовать понятные константы:
А получать нужные отрезки времени можно через метод get (). Например, узнать, какой месяц содержится в созданной нами дате можно так:
Изменить состояние объекта можно через метод set (). Например, установим новую дату у нашего объекта.
Можно сдвинуть дату на определённый период с помощью метода add (). Отодвинем дату на два месяца.
Методы getTime() и setTime() работают с объектами Date и полезны для преобразования.
Класс TimeZone
Класс TimeZone предназначен для совместного использования с классами Calendar и DateFormat. Этот класс абстрактный, поэтому от него порождать объекты нельзя. Вместо этого определен статический метод getDefault(), который возвращает экземпляр наследника TimeZone с настройками, взятыми из операционной системы, под управлением которой работает JVM.
TimeZone имеет статический метод getTimeZone(String ID), используя который можно указать наименование конкретного временного пояса, для которого необходимо получить объект TimeZone.
Набор полей, определяющих возможный набор параметров для getTimeZone, нигде явно не описывается. Но имеется статический метод getAvailableIds(), возвращающий список возможных значений наименование временных зон типа String[], который можно использовать в методе getTimeZone. Так можно определить набор возможных параметров для конкретного временного пояса относительно Гринвича String[] getAvailableIds(int offset).
Рассмотрим пример, в котором на консоль последовательно выводятся:
- временная зона по умолчанию;
- список всех возможных временных зон;
- список временных зон, которые совпадают с временной зоной Москвы.
Пример получения списка TimeZone
Код программы несложный. Метод align выполняет выравнивание для отображения смещения по времени TimeZone от среднего времени по Гринвичу GMT — времени меридиана, проходящего через прежнее место расположения Гринвичской обсерватории около Лондона. Метод drawTimeZoneParam отображает параметры TimeZone. В конструкторе класса TimeZoneList сначала определяется текущая TimeZone, после чего выводится список возможных TimeZone. И в заключении, используя метод getAvailableIDs получаем список TimeZone, у которых смещение по времени соответствует текущей зоне.
В результате работы программы в консоль будет выведена следующая информация (первый список в усеченном виде):
TimeZone UTC
В практике не часто приходится использовать различные TimeZone. Задачи, где разработчику приходится учитывать временной сдвиг, относятся к специфической деятельности человечества. Так, например, в расписании движения пассажирских поездов РФ указывается привязка к московскому и местному времени. А по какому времени ведет пассажирский состав машинист дальнего следования? Эта несложная задача решается в рамках министерства ЖД транспорта. Если состав выходит за пределы страны, то время движения (расписание) должно быть согласовано с соответствующей стороной. Аналогично это касается и полетов воздушного транспорта, где все согласования между различными аэропортами выполняются по времени UTC - всеми́рное координи́рованное вре́мя (Coordinated Universal Time).
UTC было введено вместо устаревшего среднего времени по Гринвичу (GMT), поскольку GMT является неравномерной шкалой и связана с суточным вращением Земли. Шкала UTC основана на равномерной шкале атомного времени и является более удобной для гражданского использования.
Как может влиять TimeZone, с точки зрения разработчика, на результаты работы программы? Давайте представим себе ситуацию, что время формируется на сервере (объект типа Date) и отправляется удаленному пользователю по сети. Это типично для WEB-приложений, у которых сервер и пользователи (браузеры) могут быть расположены в разных временных зонах. Для отправки объекта Date по сети (Internet) используется сериализация, позволяющая упаковать объект в набор байт на сервере и восстановить объект типа Date на клиенте (браузере). И вот здесь Вас может ожидать «засада». Если сервер и клиент имеют разные TimeZone (часовые пояса), то на клиенте будет восстановлен объект Date с временем сервера. И наоборот, если объект будет отправлен с клиента на сервер, то на сервере объект десериализуется с временем клиента.
Конечно, объект Date можно конвертировать не сервере в текстовый вид, используя DateFormat, и на клиенте его восстановить. Но Java позволяет учитывать различные TimeZone, не оказывающие влияние на сериализацию/десериализацию объектов типа Date.
Давайте рассмотрим пример TimeZoneExample (код представлен ниже), в котором время будем привязывать к одной из сторон (желательно серверной), а на компьютере устанавливать различные зоны (UTC, Москва, Владивосток). Для установки определенной временной зоны необходимо открыть в панели управления окно «Date and Time» и выбрать соответствующую TimeZone.
В примере используется три TimeZone (tm_curr, tm_utc, tm_msk - текущая, зона UTC, зона Москвы). Для двух временных зон (tm_utc, tm_msk) выводим в консоль объект Date без форматирования и с форматированием с использованием tm_utc, tm_msk и DateFormat/SimpleDateFormat.
Первоначально на компьютере устанавливаем зону UTC и получаем в консоли следующий текст :
Здесь следует сказать, что для зоны UTC и для зоны Москвы неформатированные даты (date, dt_msk) совпадают, но вот с учетом временной зоны форматированные даты отличаются на соответствующие 3 часа.
Теперь установим зону на компьютере зону Москвы и получим в консоли следующий текст :
Все как по науке - смещения по времени для дат UTC и Москвы поменялись местами. В заключении устанавливаем временную зону Владивостока :
Все соответствует действительности - объект даты создается во временной зоне Владивостока. Время для TimeZone Москвы и UTC соответствуют.
Если приложение должно работать в определенной временной зоне TimeZone, то можно, используя метод setDefault класса TimeZone, установить соответствующую временную зону в приложении при работе с датой. В примере можно было бы снять комментарий с первой строки и установить сответствующую временную зону в приложении, не оказывая влияния на временную зону в настройках компьютера.
Читайте также: