Конвертировать секунды с 01-01-1900 в метку времени в Бразилии - PullRequest
0 голосов
/ 28 ноября 2018

Я управляю устройствами, которые сообщают свои системные часы как секунды с полуночи 01-01-1900.
Мне нужно преобразовать это в метку времени.

Пока я делаю это какследующим образом:

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class TestTime
{
  // Pass seconds since 01-01-1900 00:00:00 on the command line
  public static void main(String[] args)
  {
    // ---------------------
    // Create time formatter
    // ---------------------
    SimpleDateFormat format;
    format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // ---------------------------
    // Compose 01-01-1900 00:00:00
    // ---------------------------
    Calendar cal;
    cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, 1900);
    cal.set(Calendar.MONTH, Calendar.JANUARY);
    cal.set(Calendar.DAY_OF_MONTH, 1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    // -------------------
    // Show what we've got
    // -------------------
    System.out.println(format.format(cal.getTime()));

    // ---------------------------------------------
    // Add the seconds as passed on the command line
    // ---------------------------------------------
    long secs = Long.parseLong(args[0]);
    while (secs > Integer.MAX_VALUE)
    {
      cal.add(Calendar.SECOND, Integer.MAX_VALUE);
      secs -= Integer.MAX_VALUE;
    }
    cal.add(Calendar.SECOND, (int)secs);

    // -------------------
    // Show what we've got
    // -------------------
    System.out.println(args[0] + " corresponds to " + format.format(cal.getTime()));

  } // main

} // class TestTime

При запуске этого на моем локальном компьютере (Италия, Windows 7) я получаю следующее:

java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 10:13:20

Это совершенно правильно.
Я получаюте же результаты при запуске этого на машине Linux (все еще в Италии).

Однако, запустив ту же самую программу на машине Linux в Бразилии, я получаю разные результаты:

java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 11:19:48

Независимо от того,значение, которое я передаю в командной строке, разница всегда 01: 06: 28.
Есть идеи, откуда эта разница?

Кстати, меня не волнует часовой пояс.Мне просто нужна временная метка

Обновление 1:
То же самое происходит и при использовании Java 6 (которая является реальной версией, используемой в нашей производственной среде в Бразилии).
Итак, проблема не зависит от версии Java

Обновление 2:
Проблема не возникает при вводе числа секунд ниже 441763200 (что соответствует 01-01-1914 00:00:00) Остается вопрос, почему мы получаем разницу для Бразилии?

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Взгляните на этот сайт: https://www.timeanddate.com/time/zone/brazil/sao-paulo и перейдите к изменениям часового пояса для: 1900-1924.Там вы можете увидеть смещение от -03: 06: 28 до UTC до 01-01-1914.Это та же самая причина, что и в Почему вычитание этих двух раз (в 1927 г.) дает странный результат?

0 голосов
/ 28 ноября 2018

java.time

Решение состоит в том, чтобы убедиться, что вы выполняете свое преобразование в UTC:

    Instant base = LocalDate.of(1900, Month.JANUARY, 1)
            .atStartOfDay(ZoneOffset.UTC)
            .toInstant();

    String secsSince1900String = "3752388800";
    long secsSince1900 = Long.parseLong(secsSince1900String);
    Instant target = base.plusSeconds(secsSince1900);
    System.out.println(target);

Выход (независимо от часового пояса JVM):

2018-11-28T10: 13: 20Z

Трейлинг Z на выходе означает UTC.Я проверял, устанавливая часовой пояс JVM по умолчанию для Америки / Sao_Paulo, это не имело никакого значения.При желании вы можете отформатировать дату и время по своему вкусу, например:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String formattedDateTime = target.atOffset(ZoneOffset.UTC).format(formatter);
    System.out.println(formattedDateTime);

2018-11-28 10: 13: 20

Чточто-то пошло не так при работе в Бразилии?

В Бразилии есть несколько часовых поясов.Я взял в качестве примера Сан-Паулу и с готовностью воспроизвел ваш вывод.На рубеже веков в 1900 году Сан-Паулу находился в зачете -03: 06: 28 по Гринвичу.Ваш Calendar использует часовой пояс JVM по умолчанию, поэтому вы действительно устанавливаете его время дня 03:06:28 GMT, что объясняет разницу.

Тем не менее, классы даты и времени, которые вы использовали -SimpleDateFormat и Calendar - имеют проблемы с дизайном и, к счастью, были заменены на java.time, современный API даты и времени Java, с Java 8 почти 5 лет назад.Одной из особенностей современного API является то, что мы более естественно делаем часовой пояс явным, что позволяет избежать таких проблем, как ваша, а также исправить их, если мы все равно столкнемся с ними.

Вопрос: Наша рабочая Java-версияJava 6. Могу ли я использовать java.time?

Да, java.time прекрасно работает на Java 6. Он был портирован.

  • В Java 8 и более поздних версиях и на более новом Androidустройства (от уровня API 26) современный API поставляется встроенным.
  • В Java 6 и 7 получить ThreeTen Backport, бэкпорт новых классов (ThreeTen для JSR 310; см. ссылки внизу).
  • На более старых версиях Android используется Android-версия ThreeTen Backport.Это называется ThreeTenABP.И убедитесь, что вы импортируете классы даты и времени из org.threeten.bp с подпакетами.

Ссылки

0 голосов
/ 28 ноября 2018

1 января 1914 года Бразилия изменила время и добавила 6 минут и 28 секунд к своему времени, переходящему с LMT на BRT (см. Изменения во времени в Сан-Паулу за годы, 1900-1924 ).

Дополнительная разница в один час, вероятно, заключается в том, что Бразилия охватывает 3 часовых пояса (UTC-4, UTC-3, UTC-2), и вы не указали часовой пояс в своем коде, в зависимости от системы JVMчасовой пояс.

...