Здесь нет необходимости в SimpleDateFormat
, поскольку Date
представляет количество миллисекунд с эпохи Unix , то есть полуночи января1-е 1970 (UTC).
Что может вызвать путаницу , однако, это метод toString()
, так как он применяет часовой пояс JVM по умолчанию при генерации строки, представляющей это значение.
Поскольку вы обеспокоены UTC, позвольте мне обратить ваше внимание на то, что на самом деле представляет собой Всемирное координированное время (UTC): это стандарт времени (и не часовой пояс) и это определяется высокоточными атомными часами в сочетании с вращением Земли.
Стандарт времени UTC корректировался несколько раз до 1972 года, когда были введены високосных секунд для поддержания UTC в соответствии с вращением Земли, которое не совсем ровно,и менее точный, чем атомные часы.Поскольку вращение Земли замедляется, время от времени нам приходится вставлять здесь и там дополнительные секунды:
При внутреннем значении Date
предназначен для отражения UTC, но может не соответствовать этому точно из-за этих високосных секунд.
Java 8 и новый API для даты и времени
Даже если Date
соответствует вашим потребностям, когда дело доходит до UTC, вам следует избегать этого.Это унаследованный класс сейчас.
Java 8 представила новый API для дат, времени, моментов и длительностей на основе календарной системы ISO.Ближайшим эквивалентом Date
является Instant
, который представляет временную метку, момент на временной шкале в UTC.
Чтобы зафиксировать текущий момент в UTC, вы можете использовать следующее:
Instant.now(); // Capture the current moment in UTC
И вы можете использовать следующее, чтобы получить строку, представляющую такое значение:
Instant.now().toString(); // 2019-05-17T12:50:40.474Z
Эта строка отформатирована в соответствии с ISO 8601 , где Z
указывает, что данное время указано в UTC.
Взаимодействие с JJWT
Для взаимодействия с JJWT,который пока не поддерживает типы java.time
, вы можете создать экземпляр Date
из Instant
:
Date.from(Instant.now()); // Convert from modern class to legacy class
А вот тест, который демонстрирует, как вы можете выдать и проверить токен:
@Test
public void shouldMatchIssuedAtAndExpiration() {
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
Instant issuedAt = Instant.now().truncatedTo(ChronoUnit.SECONDS);
Instant expiration = issuedAt.plus(3, ChronoUnit.MINUTES);
log.info("Issued at: {}", issuedAt);
log.info("Expires at: {}", expiration);
String jws = Jwts.builder()
.setIssuedAt(Date.from(issuedAt))
.setExpiration(Date.from(expiration))
.signWith(key)
.compact();
Claims claims = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(jws)
.getBody();
assertThat(claims.getIssuedAt().toInstant(), is(issuedAt));
assertThat(claims.getExpiration().toInstant(), is(expiration));
}
Для приведенного выше примера я использовал JJWT 0.10.5 сзависимости, перечисленные в документации .В случае необходимости приведенный выше код был написан со следующими import
инструкциями:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.security.Key;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;