package model.asn1; import model.asn1.exceptions.ParseException; import model.asn1.parsing.BytesReader; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; /** * Represents the ASN.1 UTCTime type. It encodes the time in "YYMMDDhhmm[ss]Z" string format, in UTC. * It is not named UTCTime to get around the checkstyle guidelines, but it is actually called UTCTime in X.680. */ public class UtcTime extends ASN1Time { /** * The X.680 universal class tag assignment. */ public static final Tag TAG = new Tag(TagClass.UNIVERSAL, false, 0x17); /** * Rather stupid impl ... */ private static final DateTimeFormatter FORMATTER_NO_SECS = new DateTimeFormatterBuilder() .appendPattern("yy") .appendValue(ChronoField.MONTH_OF_YEAR, 2) .appendValue(ChronoField.DAY_OF_MONTH, 2) .appendValue(ChronoField.HOUR_OF_DAY, 2) .appendValue(ChronoField.MINUTE_OF_HOUR, 2) .appendLiteral('Z') .toFormatter() .withZone(ZoneId.of("UTC")); private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder() .appendPattern("yy") .appendValue(ChronoField.MONTH_OF_YEAR, 2) .appendValue(ChronoField.DAY_OF_MONTH, 2) .appendValue(ChronoField.HOUR_OF_DAY, 2) .appendValue(ChronoField.MINUTE_OF_HOUR, 2) .optionalStart() .appendValue(ChronoField.SECOND_OF_MINUTE, 2) .optionalEnd() .appendLiteral('Z') .toFormatter() .withZone(ZoneId.of("UTC")); /** * EFFECT: Construct the UTCTime with the given tag, parentTag, and timestamp. For tag and parentTag, * consult {@link ASN1Object}. * REQUIRES: timestamp must be in UTC. */ public UtcTime(Tag tag, Tag parentTag, ZonedDateTime timestamp) { super(tag, parentTag, timestamp); } /** * EFFECT: Parse the given DER input. Time will be assumed to be in UTC. * Throws {@link ParseException} if invalid: * - The time is not in the string format specified in class specification * - Other invalid input is found. See {@link ASN1Object} for more details on parsing */ public UtcTime(BytesReader encoded, boolean hasParentTag) throws ParseException { super(encoded, hasParentTag); } /** * EFFECT: Parse the string into time, in the format specified in class specification. * Throws {@link ParseException} if the input is malformed. */ @Override public ZonedDateTime toDate(String str) throws ParseException { try { return ZonedDateTime.parse(str, FORMATTER); } catch (DateTimeParseException e) { throw new ParseException(e.getMessage()); } } /** * EFFECT: Convert the time into format "YYMMDDhhmm[ss]Z". */ @Override public String toString() { if (getTimestamp().getSecond() == 0) { return getTimestamp().format(FORMATTER_NO_SECS); } return getTimestamp().format(FORMATTER); } }