преобразование формулы localTimeDate - PullRequest
0 голосов
/ 23 апреля 2020

Я столкнулся со следующей формулой, в которой localTimeDay извлекается из TimeStamp и Timezone:

long localTimeDay = (timeStamp + timeZone) / (24 * 60 * 60 * 1000) * (24 * 60 * 60 * 1000);

Я не могу понять, что означает значение Local Time Day и как эта формула «магически» преобразуется на основе TS и TZ.

1 Ответ

2 голосов
/ 23 апреля 2020
  • timestamp - это количество миллисекунд, прошедшее с 1 января 1970 года в 00:00 UT C.
  • timeZone - это смещение в миллисекундах от UT C , Это может быть положительным, отрицательным или нулевым. Однако, чтобы формула работала, ее знак должен быть обратным: смещение +01:00 должно быть задано как минус 3 600 000 миллисекунд. Когда я добавляю смещение, я получаю другой момент времени, когда дата и время дня в UT C совпадают с исходной датой и временем дня в этом смещении UT C.
  • Деление на 24 * 60 * 60 * 1000 преобразуется из миллисекунд в дни, начиная с эпохи. Любая часть дня, то есть любое время суток, отбрасывается.
  • Умножение на 24 * 60 * 60 * 1000 переводит обратно из дней в миллисекунды. Поскольку время суток было отброшено, у нас теперь есть время в 00:00 UT C в этот день.

Так что это способ конвертации из некоторого момента времени в какое-то время UT C смещение только до даты, представленной в UT C.

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

Редактировать: Почему я считаю, что знак смещения был полностью изменен? Не может ли быть обратное преобразование из UT C в местное? Имя переменной localTimeDay, кажется, подсказывает это? Деление и умножение работает только в UT C. Поскольку эпоха в 00:00 UT C, формула обязательно дает вам начало дня в UT C, она не может дать вам начало дня с любым ненулевым смещением. Поэтому я считаю, что преобразование должно быть локальным в UT C.

Как это сделать в вашем коде

Вот хороший способ сделать то же преобразование, используя java .time, современный Java API даты и времени

    // The point in time given in UTC
    Instant time = Instant.parse("2020-04-23T05:16:45Z");
    // The UTC offset, +02:00
    ZoneOffset offset = ZoneOffset.ofHours(2);

    ZonedDateTime startOfDayInUtc = time.atOffset(offset)
            .toLocalDate()
            .atStartOfDay(ZoneOffset.UTC);
    System.out.println(startOfDayInUtc);
    long epochMillis = startOfDayInUtc.toInstant().toEpochMilli();
    System.out.println(epochMillis);

Вывод:

2020-04-23T00:00Z
1587600000000

Мы можем проверить, что он дает тот же результат, что и ваша строка кода:

    long timeStamp = time.toEpochMilli();
    // Reverse sign of offset
    long timeZone = -Duration.ofSeconds(offset.getTotalSeconds()).toMillis();
    long localTimeDay = (timeStamp + timeZone) / (24 * 60 * 60 * 1000) * (24 * 60 * 60 * 1000);

    System.out.println(localTimeDay);
    System.out.println("Agree? " + (localTimeDay == epochMillis));
1587600000000
Agree? true

Редактировать: вы спросили в комментарии:

У меня все еще есть это сомнение: существует фиксированное количество миллис, прошедших с тех пор 1 января 1970 года, поэтому каждая страна должна получить одинаковый номер. Означает ли localTimeDate «дату для моей страны» или для страны, откуда поступили эти данные? Например: Страна-А, Страна-Б; они увидят ту же миллис со времен. Предположим, что обработка данных происходит в стране-A, а источником данных является страна-B. Поэтому, когда мы говорим «localTimeDate», это относится к стране-A или стране-B.

Это будет работать для обеих стран. Все зависит от значения timeZone, которое входит в формулу. Если это смещение UT C для страны A (знак обратный), преобразование будет происходить из времени страны A в дату UT C. Если это смещение страны B, конвертация будет из страны B времени. И вы полностью правы, вы получите две разные даты, если в странах A и B это будет не одна и та же дата, что может быть легко.

...