Как преобразовать временную метку Google Proto в Java LocalDate? - PullRequest
0 голосов
/ 04 октября 2018

Нам нужно преобразовать временную метку буфера Google Proto в обычную дату.При таких обстоятельствах есть ли способ напрямую преобразовать временную метку буфера Google Proto в Java LocalDate?

Ответы [ 3 ]

0 голосов
/ 04 октября 2018

Сначала несколько замечаний: * Protobuf TimeStamp имеет более высокое разрешение (секунды и доли секунды), чем LocalDate (дни) в Java, поэтому вы потеряете некоторую информацию, преобразовав из TimeStamp в LocalDate

См. Эту выдержку из TimeStamp JavaDoc :

Метка времени представляет собой точку во времени, независимую от любого часового пояса или календаря, представленную в секундах и долях секунд вРазрешение наносекунды во время UTC Epoch.


Этот же JavaDoc говорит нам, что значение является представлением, основанным на времени Epoch, что означает, что мы можем использовать Java LocalDateTime # ofEpochSeconds конвертировать без потерь (потому что LocalDateTime также сохраняет время) и отсюда время, чтобы получить LocalDate.

Используя LocalDateTime (em: Local), мы можем убедиться, что мыиспользуйте то же смещение TimeZone, что и класс TimeStamp, то есть UTC (то есть снова из JavaDoc):

final Timestamp ts1 = Timestamp.newBuilder().setSeconds((60 * 60 * 24) - 1).build();
final Timestamp ts2 = Timestamp.newBuilder().setSeconds((60 * 60 * 24)).build();

final LocalDate ld1 = LocalDateTime.ofEpochSecond(ts1.getSeconds(), ts1.getNanos(), ZoneOffset.UTC).toLocalDate();
final LocalDate ld2 = LocalDateTime.ofEpochSecond(ts2.getSeconds(), ts2.getNanos(), ZoneOffset.UTC).toLocalDate();

System.out.println(ts1 + " = " + ld1);
System.out.println(ts2 + " = " + ld2);

Вывод

секунд: 86399 = 1970-01-01

секунд: 86400 = 1970-01-02


РЕДАКТИРОВАТЬ после запроса преобразования в java.util.Date

Поиск возможных конструкторов для Dateи их JavaDoc мы находим:

Выделяет объект Date и инициализирует его для представления указанного количества миллисекунд со стандартного базового времени, известного как "эпоха", а именно 1 января, 1970, 00:00:00 по Гринвичу.

И поскольку GMT является более старым стандартом для зонированного представления времени и в основном это UTC +/- 0, этот конструктор соответствует нашим потребностям:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// making sure the Date objects use UTC as timezone

final Timestamp ts1 = Timestamp.newBuilder().setSeconds((60 * 60 * 24) - 1).build();
final Timestamp ts2 = Timestamp.newBuilder().setSeconds((60 * 60 * 24)).build();

final Date d1 = new Date(ts1.getSeconds() * 1000);
final Date d2 = new Date(ts2.getSeconds() * 1000);

System.out.println(ts1 + " = " + d1);
System.out.println(ts2 + " = " + d2);

Вывод:

секунд: 86399 = чт 01 января 23:59:59 CET 1970

секунд: 86400 = пт 02 января 00:00:00 CET 1970

0 голосов
/ 04 октября 2018

tl; dr

Как момент в UTC, преобразовать в java.time.Instant.Затем примените часовой пояс, чтобы получить ZonedDateTime.Извлечь часть только для даты как LocalDate.

Однострочник:

Instant
.ofEpochSecond( ts.getSeconds() , ts.getNanos() ) 
.atZone( ZoneId.of( "America/Montreal" ) ) 
.toLocalDate() 

Преобразование

Первый шаг - преобразование количества секунд и доли секунды (* наносимых на секунду) объекта Timestamp* 1015 (наносекунд) к классам java.time .В частности, java.time.Instant.Как и Timestamp, Instant представляет момент в UTC с разрешением наносекунд.

Instant instant =  Instant.ofEpochSecond( ts.getSeconds() , ts.getNanos() ) ;

Для определения даты требуется часовой пояс.В любой момент времени дата меняется по всему земному шару в зависимости от зоны.

Примените ZoneId к нашему Instant, чтобы получить ZonedDateTime.Тот же самый момент, та же самая точка на временной шкале, другое время настенных часов.

ZoneId z = ZoneId( "Pacific/Auckland" ) ; 
ZonedDateTime zdt = instant.atZone( z ) ;

Извлечь часть только для даты в виде LocalDateLocalDate нет времени суток и часового пояса.

LocalDate ld = zdt.toLocalDate() ;

Осторожно: не используйте для этой цели класс LocalDateTime, как, к сожалению, показано в другом ответе.В этом классе намеренно отсутствует понятие часового пояса или смещения от UTC.Как таковой, он не может представлять момент, не является точкой на временной шкале.Смотрите документацию класса.

Конвертировать

Лучше всего полностью избегать ужасно утомительных устаревших классов даты и времени, включая Date, Calendar, SimpleDateFormat.Но если вам необходимо взаимодействовать со старым кодом, который еще не обновлен до java.time , вы можете конвертировать туда и обратно.Вызовите новые методы преобразования, добавленные к старым классам.

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;

Чтобы представить значение только для даты как GregorianCalendar, мы должны указать время суток и часовой пояс.Скорее всего, вы захотите использовать первое время дня в качестве компонента времени суток.Никогда не предполагайте, что первый момент 00:00:00.Аномалии, такие как переход на летнее время, означают, что первым моментом может быть другое время, например 01:00:00.Пусть java.time определит первый момент.

ZonedDateTime firstMomentOfDay = ld.atZone( z ) ;
GregorianCalendar gc = GregorianCalendar.from( firstMomentOfDay ) ;

О java.time

Среда java.time встроена в Java 8и позже.Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами непосредственно с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии пакетов Android для реализации java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

Проект ThreeTen-Extra расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

0 голосов
/ 04 октября 2018

Самый простой способ сделать это - извлечь дату из временной метки буфера в String , чтобы ее можно было многократно использовать, а затем:

Timestamp timestamp;
String sDate1 = timestamp.toString();  
Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse(sDate1);

В случае, если вы хотите сделатьВ LocalDate вы делаете следующее:

Timestamp timestamp;
String sDate1 = timestamp.toString();    
LocalDate localDate = LocalDate.parse(sDate1);

Если вы не можете извлечь временную метку String и у вас есть миллисекунды, вы также можете создать объект LocalDate и Date из этого, так как у них обоих есть подрядчики для этого..

    Timestamp timestamp;
    long timeInMilliSeconds = Timestamp.toMillis(timestamp);
    Date currentDate = new Date(timeInMilliSeconds);
    LocalDate date = Instant.ofEpochMilli(timeInMilliSeconds).atZone(ZoneId.systemDefault()).toLocalDate();
...