Repository: microsoft/gctoolkit
File: api/src/main/java/com/microsoft/gctoolkit/time/DateTimeStamp.java (Java)

Code before:
 * Instance of DateTimeStamp are created by the parser. The constructors match what might be
 * found for dates and time stamps in a GC log file.
 */

public class DateTimeStamp implements Comparable<DateTimeStamp> {
    // Represents the time from Epoch
    // In the case where we have timestamps, the epoch is start of JVM
    // In the case where we only have date stamps, the epoch is 1970:01:01:00:00:00.000::UTC+0
    // All calculations in GCToolKit make use of the double, timeStamp.
    // Calculations are based on an startup Epoch of 0.000 seconds. This isn't always the case and
    // certainly isn't the case when only date stamp is present. In these cases, start time is estimated.
    // This is surprisingly difficult to do thus use of timestamp is highly recommended.

    // Requirements
    // Timestamp can never be less than 0
    //      - use NaN to say it's not set
    public final static double TIMESTAMP_NOT_SET = Double.NaN;
    private final ZonedDateTime dateTime;
    private double timeStamp;
    public static final Comparator<DateTimeStamp> comparator = getComparator();

    // For some reason, ISO_DATE_TIME doesn't like that time-zone is -0100. It wants -01:00.
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

    private static ZonedDateTime dateFromString(String iso8601DateTime) {
        if ( iso8601DateTime == null)
            return null;
        return ZonedDateTime.from(formatter.parse(iso8601DateTime));
    }

    private static double ageFromString(String doubleFormat) {
        if ( doubleFormat == null) return TIMESTAMP_NOT_SET;
        return Double.parseDouble(doubleFormat.replace(",","."));
    }

    // Patterns needed to support conversion of a log line to a DateTimeStamp

    private static final String DECIMAL_POINT = "(?:\\.|,)";
    private static final String INTEGER = "\\d+";
    private static final String DATE = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}[\\+|\\-]\\d{4}";
    private static final String TIME = INTEGER + DECIMAL_POINT + "\\d{3}";

    // Unified Tokens
    private static final String DATE_TAG = "\\[" + DATE + "\\]";
    private static final String UPTIME_TAG = "\\[(" + TIME + ")s\\]";

    // Pre-unified tokens
    private static final String TIMESTAMP = "(" + TIME + "): ";
    private static final String DATE_STAMP = "(" + DATE + "): ";
    private static final String DATE_TIMESTAMP = "^(?:" + DATE_STAMP + ")?" + TIMESTAMP;


Review comment (suggestion):
```suggestion
        if (iso8601DateTime == null)
```

Code after:
 * Instance of DateTimeStamp are created by the parser. The constructors match what might be
 * found for dates and time stamps in a GC log file.
 */

public class DateTimeStamp implements Comparable<DateTimeStamp> {
    // Represents the time from Epoch
    // In the case where we have timestamps, the epoch is start of JVM
    // In the case where we only have date stamps, the epoch is 1970:01:01:00:00:00.000::UTC+0
    // All calculations in GCToolKit make use of the double, timeStamp.
    // Calculations are based on an startup Epoch of 0.000 seconds. This isn't always the case and
    // certainly isn't the case when only date stamp is present. In these cases, start time is estimated.
    // This is surprisingly difficult to do thus use of timestamp is highly recommended.

    // Requirements
    // Timestamp can never be less than 0
    //      - use NaN to say it's not set
    public final static double TIMESTAMP_NOT_SET = Double.NaN;
    private final ZonedDateTime dateTime;
    private double timeStamp;
    public static final Comparator<DateTimeStamp> comparator = getComparator();

    // For some reason, ISO_DATE_TIME doesn't like that time-zone is -0100. It wants -01:00.
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

    private static ZonedDateTime dateFromString(String iso8601DateTime) {
        if (iso8601DateTime == null)
            return null;
        return ZonedDateTime.from(formatter.parse(iso8601DateTime));
    }

    private static double ageFromString(String doubleFormat) {
        if ( doubleFormat == null) return TIMESTAMP_NOT_SET;
        return Double.parseDouble(doubleFormat.replace(",","."));
    }

    // Patterns needed to support conversion of a log line to a DateTimeStamp

    private static final String DECIMAL_POINT = "(?:\\.|,)";
    private static final String INTEGER = "\\d+";
    private static final String DATE = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}[\\+|\\-]\\d{4}";
    private static final String TIME = INTEGER + DECIMAL_POINT + "\\d{3}";

    // Unified Tokens
    private static final String DATE_TAG = "\\[" + DATE + "\\]";
    private static final String UPTIME_TAG = "\\[(" + TIME + ")s\\]";

    // Pre-unified tokens
    private static final String TIMESTAMP = "(" + TIME + "): ";
    private static final String DATE_STAMP = "(" + DATE + "): ";
    private static final String DATE_TIMESTAMP = "^(?:" + DATE_STAMP + ")?" + TIMESTAMP;