Skip to content

Latest commit

 

History

History
115 lines (79 loc) · 13.9 KB

intro.md

File metadata and controls

115 lines (79 loc) · 13.9 KB

Дата и время в Java

Введение

Работа с датой и временем - это то, что необходимо практически в любой системе и приложении. И вы гарантировано с этим столкнетесь, именно поэтому надо знать как это устроено и как работать с этим в Java.

Прежде всего стоит сразу сказать, что единицей измерения времени считается - секунда. Дадим определение секунды:

Секунда — время, равное 9 192 631 770 периодам излучения, соответствующего переходу между двумя сверхтонкими уровнями основного состояния атома цезия-133.

Я знаю, что русскоязычная википедия не всегда бывает точна и очень часто уступает своей англоязычной версии, но для простоты восприятия и так как я сам пишу свои заметки на русском - я решил давать ссылки именно на русскоязычную версию.

Если вы пришли с физическим бэкграундом, то можете задать языку программирования Java несколько вопросов - например, учитывает ли Java, что скорость течения времени зависит от скорости перемещения объекта?

Сразу скажу - нет, текущая Java не учитывает никакие релятивистские эффекты, так как не считает, что кто-то движется на около-световых скоростях. Также считается, что ось времени одна и едина для всех.

Теперь перейдем к более низменным задачам, чем рассчет времени при движениях близких к скорости света.

И даже тут не все так просто - особенно, если мы разрабатываем не локальный сервис.

Приведем пример: пусть в какой-то определенный момент в одной точке мира происходит событие. В зависимости от географического положения время этого события будет для разное пользователей. Ведь существуют временные зоны, разные календари и прочее. Если у нас есть сервис, который развернут в Москве, а событие происходит в Иркутске или вообще на другом континенте - то такой запрос будет обработан не моментально.

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

В мире ИТ и в Java в частности - данная точка - это Unix-time. Это временная точка с меткой 00:00:00 1 января 1970.

Чтобы на пальцах объяснить как это нам поможет и работает - представьте себя и вашего друга с песочными часами. Вы одновременно переворачиваете часы и расходитесь по миру. Теперь времена событий вы сообщаете как высоту песка в часах.

С Unix-time то же самое, только вместо точки переворота часов - начало Unix-time, а вместо высоты песочного столбика - количество миллисекунд, прошедших с того момента.

Теперь, когда более-менее прояснили то, как можно сообщить в какой момент времени произошло некоторое событие, давайте вспомним, что тогда, когда в Москве вечер - в Иркутске вообще ночь. Происходит это - из-за вращения Земли вокруг своей оси.

Стремление учесть это вращение, а также определить территории с примерно одинаковым местным световым временем породило формирование часовых поясов или time zones, т.е некоторых временных зон.

Временные зоны

В результате этого было сформировано 24 часовых пояса, точкой отсчета был принят гринвичский меридиан - нулевой.

Отсюда следует, что когда говорят, например, о встрече 9 марта 2018 14:00:00 - необходимо добавлять временную зону, так как метка 9 марта 2018 14:00:00 на временной оси соответствует сразу нескольким точкам. Поэтому подобная встреча должна назначаться в например виде: 9 марта 2018 в 14:00:00 MSK. Для примера приведем вывод одной и той же временной точки на временной оси в зависимости от временной зоны:

Fri Mar  9 7:37:00 UTC 2018
Fri Mar  9 10:37:00 MSK 2018

Что же является основой для часовых поясов? Откуда идет отсчет во временных зонах? И тут важно сказать пару слов о UTC и GMT.

UTC и GMT

GMT - Greenwich Mean Time - это time zone, часовой пояс, который официально используется в некоторых Европейских странах. GMT вычисляется астрономически по положению Земли относительно других объектов. До 1972 года гринвическое время считалось точкой отсчета времени в других часовых поясах.

Однако, ныне в этом качестве выступает UTC - почему? Дело в том, что из-за не равномерного вращения Земли - земной шар оказывается в одном и том же положении не через одинаковый промежуток времени - этот промежуток растет. Вспоминаем, что определение одной секунды - это:

Секунда — время, равное 9 192 631 770 периодам излучения, соответствующего переходу между двумя сверхтонкими уровнями основного состояния атома цезия-133.

А значит, что расстояние между временными точками по соседним меткам по GMT - например 14:00:01 и 14:00:02 - может точно не равняться секунде.

Именно из-за подобных проблем было введено UTC.

UTC - Coordinated Universal Time - уже рассчитывается по атомным часам, не является time zone, а является time standard, который используется как основа для часовых поясов и времени по всему миру. Это значит, что ни одна из стран официально не использует UTC как свое локальное время.

В UTC расстояние между временными точками по соседним меткам - например 14:00:01 и 14:00:02 - всегда строго равно одной секунде.

Так как выше было рассказано - что Земля вращается неравномерно, то возникает вопрос - нет ли у UTC с этим каких-то проблем? Да, вопроса с точностью между двумя врменными точками уже не стоит, но из-за вращения Земли возникает другая проблема - теперь необходимо UTC время согласовать с GMT временем - ведь будет накапливаться отличие солнечного времени от UTC - будет сдвигаться время дня и ночи!

Для решения проблемы было введено понятие leap second - секунды координации. По правилам вставки секунды координации на текущую дату - 09 марта 2018:

Секунда координации добавляется по астрономическим наблюдениям в конце суток по всемирному времени 30 июня или 31 декабря так, чтобы время UTC не отличалось от UT1 более, чем на ±0,9 секунды. Считается, что в такие дни после времени 23:59:59 идёт 23:59:60.

Таким образом - разница между точками с одинаковыми метками в GMT и UTC никогда не превышает одной секунды.

А вот в Unix-time никаких leap second нет. И для соответствия времени по UTC используется просто перевод времени на секунду назад в полночь. Выглядит это как-то так:

23:59:58
23:59:59
23:59:59
00:00:00

Из-за этого для Java - так как там все завязано на Unix-time количество секунд между 23:59:59 и 00:01:00 следующего дня составляет 120 секунд - вместо положенных 121. Получается, что одна секунда пропадает - мы ее съедаем, отсюда можно сделать вывод - на текущей JVM строить машину времени бесмысслено - точное количество секунд, на которое надо откатиться будет рассчитать крайне затруднительно.

Кстати говоря, в 2009 году Международный астрономический союз предложил отказаться от leap second - как раз таки из-за неравномерного вращения Земли - вращение нашей планеты замедляется и корреляцию с leap second приходится производить все чаще - это никак нельзя назвать удобным, поэтому MAC предложил просто каждые 6000 лет прибавлять к UTC час!

Решение по данному вопросу, насколько я знаю из Википедии, отложено до 2023.

Календарь

Стоит отметить, что все, о чем мы здесь говорим - применимо к григорианскому календарю, так как данный календарь считается сейчас стандартом - большая часть Земли(но не все) договорилась использовать его. Считается, что в году 365 дней, однако, Земля делает оборот вокруг Солнца за примерно 365 суток 5 часов и 49 минут. А это значит, что наподобие leap second нам надо ввести и leap year - чтобы как-то провести корреляцию. Для этой цели и ввели понятие Високосный год - год, в котором добавляется один день к февралю - 29 февраля. Год является високосным в двух случаях: либо он кратен 4, но при этом не кратен 100, либо кратен 400. Год не является високосным, если он не кратен 4, либо он кратен 100, но при этом не кратен 400.

Теперь, вернемся к Java.

В Java на данный момент мне извесны следующие библиотеки и классы для работы со временем: