From 689a3ae996227c49c669977f5c583da6c17193aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Thu, 9 Dec 2021 16:03:31 +0100 Subject: [PATCH 1/7] add util class --- .../gson/internal/bind/util/ISO8601Utils.java | 362 ++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java diff --git a/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java b/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java new file mode 100644 index 0000000000..b812c7c568 --- /dev/null +++ b/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java @@ -0,0 +1,362 @@ +package io.sentry.vendor.gson.internal.bind.util; + +import org.jetbrains.annotations.ApiStatus; + +// Source: https://github.com/google/gson +// Tag: gson-parent-2.8.9 +// Commit Hash: 6a368d89da37917be7714c3072b8378f4120110a +// Changes: @ApiStatus.Internal, SuppressWarnings, Disable `JsonReaderInternalAccess.INSTANCE` & Imports + +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.*; + +/** + * Utilities methods for manipulating dates in iso8601 format. This is much much faster and GC friendly than using SimpleDateFormat so + * highly suitable if you (un)serialize lots of date objects. + * + * Supported parse format: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:]mm]] + * + * @see this specification + */ +//Date parsing code from Jackson databind ISO8601Utils.java +// https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/util/ISO8601Utils.java +@SuppressWarnings({"TryWithIdenticalCatches", "UnusedAssignment", "MagicConstant"}) // Ignore warnings to preserve original code. +@ApiStatus.Internal +public class ISO8601Utils +{ + /** + * ID to represent the 'UTC' string, default timezone since Jackson 2.7 + * + * @since 2.7 + */ + private static final String UTC_ID = "UTC"; + /** + * The UTC timezone, prefetched to avoid more lookups. + * + * @since 2.7 + */ + private static final TimeZone TIMEZONE_UTC = TimeZone.getTimeZone(UTC_ID); + + /* + /********************************************************** + /* Formatting + /********************************************************** + */ + + /** + * Format a date into 'yyyy-MM-ddThh:mm:ssZ' (default timezone, no milliseconds precision) + * + * @param date the date to format + * @return the date formatted as 'yyyy-MM-ddThh:mm:ssZ' + */ + public static String format(Date date) { + return format(date, false, TIMEZONE_UTC); + } + + /** + * Format a date into 'yyyy-MM-ddThh:mm:ss[.sss]Z' (GMT timezone) + * + * @param date the date to format + * @param millis true to include millis precision otherwise false + * @return the date formatted as 'yyyy-MM-ddThh:mm:ss[.sss]Z' + */ + public static String format(Date date, boolean millis) { + return format(date, millis, TIMEZONE_UTC); + } + + /** + * Format date into yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm] + * + * @param date the date to format + * @param millis true to include millis precision otherwise false + * @param tz timezone to use for the formatting (UTC will produce 'Z') + * @return the date formatted as yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm] + */ + public static String format(Date date, boolean millis, TimeZone tz) { + Calendar calendar = new GregorianCalendar(tz, Locale.US); + calendar.setTime(date); + + // estimate capacity of buffer as close as we can (yeah, that's pedantic ;) + int capacity = "yyyy-MM-ddThh:mm:ss".length(); + capacity += millis ? ".sss".length() : 0; + capacity += tz.getRawOffset() == 0 ? "Z".length() : "+hh:mm".length(); + StringBuilder formatted = new StringBuilder(capacity); + + padInt(formatted, calendar.get(Calendar.YEAR), "yyyy".length()); + formatted.append('-'); + padInt(formatted, calendar.get(Calendar.MONTH) + 1, "MM".length()); + formatted.append('-'); + padInt(formatted, calendar.get(Calendar.DAY_OF_MONTH), "dd".length()); + formatted.append('T'); + padInt(formatted, calendar.get(Calendar.HOUR_OF_DAY), "hh".length()); + formatted.append(':'); + padInt(formatted, calendar.get(Calendar.MINUTE), "mm".length()); + formatted.append(':'); + padInt(formatted, calendar.get(Calendar.SECOND), "ss".length()); + if (millis) { + formatted.append('.'); + padInt(formatted, calendar.get(Calendar.MILLISECOND), "sss".length()); + } + + int offset = tz.getOffset(calendar.getTimeInMillis()); + if (offset != 0) { + int hours = Math.abs((offset / (60 * 1000)) / 60); + int minutes = Math.abs((offset / (60 * 1000)) % 60); + formatted.append(offset < 0 ? '-' : '+'); + padInt(formatted, hours, "hh".length()); + formatted.append(':'); + padInt(formatted, minutes, "mm".length()); + } else { + formatted.append('Z'); + } + + return formatted.toString(); + } + + /* + /********************************************************** + /* Parsing + /********************************************************** + */ + + /** + * Parse a date from ISO-8601 formatted string. It expects a format + * [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:mm]]] + * + * @param date ISO string to parse in the appropriate format. + * @param pos The position to start parsing from, updated to where parsing stopped. + * @return the parsed date + * @throws ParseException if the date is not in the appropriate format + */ + public static Date parse(String date, ParsePosition pos) throws ParseException { + Exception fail = null; + try { + int offset = pos.getIndex(); + + // extract year + int year = parseInt(date, offset, offset += 4); + if (checkOffset(date, offset, '-')) { + offset += 1; + } + + // extract month + int month = parseInt(date, offset, offset += 2); + if (checkOffset(date, offset, '-')) { + offset += 1; + } + + // extract day + int day = parseInt(date, offset, offset += 2); + // default time value + int hour = 0; + int minutes = 0; + int seconds = 0; + int milliseconds = 0; // always use 0 otherwise returned date will include millis of current time + + // if the value has no time component (and no time zone), we are done + boolean hasT = checkOffset(date, offset, 'T'); + + if (!hasT && (date.length() <= offset)) { + Calendar calendar = new GregorianCalendar(year, month - 1, day); + + pos.setIndex(offset); + return calendar.getTime(); + } + + if (hasT) { + + // extract hours, minutes, seconds and milliseconds + hour = parseInt(date, offset += 1, offset += 2); + if (checkOffset(date, offset, ':')) { + offset += 1; + } + + minutes = parseInt(date, offset, offset += 2); + if (checkOffset(date, offset, ':')) { + offset += 1; + } + // second and milliseconds can be optional + if (date.length() > offset) { + char c = date.charAt(offset); + if (c != 'Z' && c != '+' && c != '-') { + seconds = parseInt(date, offset, offset += 2); + if (seconds > 59 && seconds < 63) seconds = 59; // truncate up to 3 leap seconds + // milliseconds can be optional in the format + if (checkOffset(date, offset, '.')) { + offset += 1; + int endOffset = indexOfNonDigit(date, offset + 1); // assume at least one digit + int parseEndOffset = Math.min(endOffset, offset + 3); // parse up to 3 digits + int fraction = parseInt(date, offset, parseEndOffset); + // compensate for "missing" digits + switch (parseEndOffset - offset) { // number of digits parsed + case 2: + milliseconds = fraction * 10; + break; + case 1: + milliseconds = fraction * 100; + break; + default: + milliseconds = fraction; + } + offset = endOffset; + } + } + } + } + + // extract timezone + if (date.length() <= offset) { + throw new IllegalArgumentException("No time zone indicator"); + } + + TimeZone timezone = null; + char timezoneIndicator = date.charAt(offset); + + if (timezoneIndicator == 'Z') { + timezone = TIMEZONE_UTC; + offset += 1; + } else if (timezoneIndicator == '+' || timezoneIndicator == '-') { + String timezoneOffset = date.substring(offset); + + // When timezone has no minutes, we should append it, valid timezones are, for example: +00:00, +0000 and +00 + timezoneOffset = timezoneOffset.length() >= 5 ? timezoneOffset : timezoneOffset + "00"; + + offset += timezoneOffset.length(); + // 18-Jun-2015, tatu: Minor simplification, skip offset of "+0000"/"+00:00" + if ("+0000".equals(timezoneOffset) || "+00:00".equals(timezoneOffset)) { + timezone = TIMEZONE_UTC; + } else { + // 18-Jun-2015, tatu: Looks like offsets only work from GMT, not UTC... + // not sure why, but that's the way it looks. Further, Javadocs for + // `java.util.TimeZone` specifically instruct use of GMT as base for + // custom timezones... odd. + String timezoneId = "GMT" + timezoneOffset; +// String timezoneId = "UTC" + timezoneOffset; + + timezone = TimeZone.getTimeZone(timezoneId); + + String act = timezone.getID(); + if (!act.equals(timezoneId)) { + /* 22-Jan-2015, tatu: Looks like canonical version has colons, but we may be given + * one without. If so, don't sweat. + * Yes, very inefficient. Hopefully not hit often. + * If it becomes a perf problem, add 'loose' comparison instead. + */ + String cleaned = act.replace(":", ""); + if (!cleaned.equals(timezoneId)) { + throw new IndexOutOfBoundsException("Mismatching time zone indicator: "+timezoneId+" given, resolves to " + +timezone.getID()); + } + } + } + } else { + throw new IndexOutOfBoundsException("Invalid time zone indicator '" + timezoneIndicator+"'"); + } + + Calendar calendar = new GregorianCalendar(timezone); + calendar.setLenient(false); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month - 1); + calendar.set(Calendar.DAY_OF_MONTH, day); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minutes); + calendar.set(Calendar.SECOND, seconds); + calendar.set(Calendar.MILLISECOND, milliseconds); + + pos.setIndex(offset); + return calendar.getTime(); + // If we get a ParseException it'll already have the right message/offset. + // Other exception types can convert here. + } catch (IndexOutOfBoundsException e) { + fail = e; + } catch (NumberFormatException e) { + fail = e; + } catch (IllegalArgumentException e) { + fail = e; + } + String input = (date == null) ? null : ('"' + date + '"'); + String msg = fail.getMessage(); + if (msg == null || msg.isEmpty()) { + msg = "("+fail.getClass().getName()+")"; + } + ParseException ex = new ParseException("Failed to parse date [" + input + "]: " + msg, pos.getIndex()); + ex.initCause(fail); + throw ex; + } + + /** + * Check if the expected character exist at the given offset in the value. + * + * @param value the string to check at the specified offset + * @param offset the offset to look for the expected character + * @param expected the expected character + * @return true if the expected character exist at the given offset + */ + private static boolean checkOffset(String value, int offset, char expected) { + return (offset < value.length()) && (value.charAt(offset) == expected); + } + + /** + * Parse an integer located between 2 given offsets in a string + * + * @param value the string to parse + * @param beginIndex the start index for the integer in the string + * @param endIndex the end index for the integer in the string + * @return the int + * @throws NumberFormatException if the value is not a number + */ + private static int parseInt(String value, int beginIndex, int endIndex) throws NumberFormatException { + if (beginIndex < 0 || endIndex > value.length() || beginIndex > endIndex) { + throw new NumberFormatException(value); + } + // use same logic as in Integer.parseInt() but less generic we're not supporting negative values + int i = beginIndex; + int result = 0; + int digit; + if (i < endIndex) { + digit = Character.digit(value.charAt(i++), 10); + if (digit < 0) { + throw new NumberFormatException("Invalid number: " + value.substring(beginIndex, endIndex)); + } + result = -digit; + } + while (i < endIndex) { + digit = Character.digit(value.charAt(i++), 10); + if (digit < 0) { + throw new NumberFormatException("Invalid number: " + value.substring(beginIndex, endIndex)); + } + result *= 10; + result -= digit; + } + return -result; + } + + /** + * Zero pad a number to a specified length + * + * @param buffer buffer to use for padding + * @param value the integer value to pad if necessary. + * @param length the length of the string we should zero pad + */ + private static void padInt(StringBuilder buffer, int value, int length) { + String strValue = Integer.toString(value); + for (int i = length - strValue.length(); i > 0; i--) { + buffer.append('0'); + } + buffer.append(strValue); + } + + /** + * Returns the index of the first character in the string that is not a digit, starting at offset. + */ + private static int indexOfNonDigit(String string, int offset) { + for (int i = offset; i < string.length(); i++) { + char c = string.charAt(i); + if (c < '0' || c > '9') return i; + } + return string.length(); + } + +} + From 2455535bcdfac33a93f8589e7ac18080a63609a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Thu, 9 Dec 2021 16:21:04 +0100 Subject: [PATCH 2/7] add tests --- .../gson/internal/bind/util/ISO8601Utils.java | 2 +- .../internal/bind/util/ISO8601UtilsTest.java | 100 ++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 sentry/src/test/java/io/sentry/vendor/gson/internal/bind/util/ISO8601UtilsTest.java diff --git a/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java b/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java index b812c7c568..2a0fd05e95 100644 --- a/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java +++ b/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java @@ -5,7 +5,7 @@ // Source: https://github.com/google/gson // Tag: gson-parent-2.8.9 // Commit Hash: 6a368d89da37917be7714c3072b8378f4120110a -// Changes: @ApiStatus.Internal, SuppressWarnings, Disable `JsonReaderInternalAccess.INSTANCE` & Imports +// Changes: @ApiStatus.Internal, SuppressWarnings import java.text.ParseException; import java.text.ParsePosition; diff --git a/sentry/src/test/java/io/sentry/vendor/gson/internal/bind/util/ISO8601UtilsTest.java b/sentry/src/test/java/io/sentry/vendor/gson/internal/bind/util/ISO8601UtilsTest.java new file mode 100644 index 0000000000..1352abd0cd --- /dev/null +++ b/sentry/src/test/java/io/sentry/vendor/gson/internal/bind/util/ISO8601UtilsTest.java @@ -0,0 +1,100 @@ +package io.sentry.vendor.gson.internal.bind.util; + +// Source: https://github.com/google/gson +// Tag: gson-parent-2.8.9 +// Commit Hash: 6a368d89da37917be7714c3072b8378f4120110a +// Changes: -- + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.*; + +import static org.junit.Assert.assertEquals; + +public class ISO8601UtilsTest { + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + private static TimeZone utcTimeZone() { + return TimeZone.getTimeZone("UTC"); + } + + private static GregorianCalendar createUtcCalendar() { + TimeZone utc = utcTimeZone(); + GregorianCalendar calendar = new GregorianCalendar(utc); + // Calendar was created with current time, must clear it + calendar.clear(); + return calendar; + } + + @Test + public void testDateFormatString() { + GregorianCalendar calendar = new GregorianCalendar(utcTimeZone(), Locale.US); + // Calendar was created with current time, must clear it + calendar.clear(); + calendar.set(2018, Calendar.JUNE, 25); + Date date = calendar.getTime(); + String dateStr = ISO8601Utils.format(date); + String expectedDate = "2018-06-25"; + assertEquals(expectedDate, dateStr.substring(0, expectedDate.length())); + } + + @Test + public void testDateFormatWithMilliseconds() { + long time = 1530209176870L; + Date date = new Date(time); + String dateStr = ISO8601Utils.format(date, true); + String expectedDate = "2018-06-28T18:06:16.870Z"; + assertEquals(expectedDate, dateStr); + } + + @Test + public void testDateFormatWithTimezone() { + long time = 1530209176870L; + Date date = new Date(time); + String dateStr = ISO8601Utils.format(date, true, TimeZone.getTimeZone("Brazil/East")); + String expectedDate = "2018-06-28T15:06:16.870-03:00"; + assertEquals(expectedDate, dateStr); + } + + @Test + public void testDateParseWithDefaultTimezone() throws ParseException { + String dateStr = "2018-06-25"; + Date date = ISO8601Utils.parse(dateStr, new ParsePosition(0)); + Date expectedDate = new GregorianCalendar(2018, Calendar.JUNE, 25).getTime(); + assertEquals(expectedDate, date); + } + + @Test + public void testDateParseWithTimezone() throws ParseException { + String dateStr = "2018-06-25T00:00:00-03:00"; + Date date = ISO8601Utils.parse(dateStr, new ParsePosition(0)); + GregorianCalendar calendar = createUtcCalendar(); + calendar.set(2018, Calendar.JUNE, 25, 3, 0); + Date expectedDate = calendar.getTime(); + assertEquals(expectedDate, date); + } + + @Test + public void testDateParseSpecialTimezone() throws ParseException { + String dateStr = "2018-06-25T00:02:00-02:58"; + Date date = ISO8601Utils.parse(dateStr, new ParsePosition(0)); + GregorianCalendar calendar = createUtcCalendar(); + calendar.set(2018, Calendar.JUNE, 25, 3, 0); + Date expectedDate = calendar.getTime(); + assertEquals(expectedDate, date); + } + + @Test + public void testDateParseInvalidTime() throws ParseException { + String dateStr = "2018-06-25T61:60:62-03:00"; + exception.expect(ParseException.class); + ISO8601Utils.parse(dateStr, new ParsePosition(0)); + } +} + From 24cd5097bfcb6f043ef3dee3d03df28bc3c78661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Thu, 9 Dec 2021 16:39:54 +0100 Subject: [PATCH 3/7] replace usage of SimpleDateFormat --- sentry/src/main/java/io/sentry/DateUtils.java | 40 ++----------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/sentry/src/main/java/io/sentry/DateUtils.java b/sentry/src/main/java/io/sentry/DateUtils.java index d24bf1c34c..01d989b85b 100644 --- a/sentry/src/main/java/io/sentry/DateUtils.java +++ b/sentry/src/main/java/io/sentry/DateUtils.java @@ -1,13 +1,12 @@ package io.sentry; +import io.sentry.vendor.gson.internal.bind.util.ISO8601Utils; import java.math.BigDecimal; import java.math.RoundingMode; -import java.text.DateFormat; import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.text.ParsePosition; import java.util.Calendar; import java.util.Date; -import java.util.Locale; import java.util.TimeZone; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -16,34 +15,10 @@ @ApiStatus.Internal public final class DateUtils { private static final String UTC = "UTC"; - // ISO 8601 - private static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - private static final String ISO_FORMAT_WITH_MILLIS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; // if UTC is not found, it fallback to "GMT" which is UTC equivalent private static final @NotNull TimeZone UTC_TIMEZONE = TimeZone.getTimeZone(UTC); - private static final @NotNull ThreadLocal SDF_ISO_FORMAT_WITH_MILLIS_UTC = - new ThreadLocal() { - @Override - protected SimpleDateFormat initialValue() { - final SimpleDateFormat simpleDateFormat = - new SimpleDateFormat(ISO_FORMAT_WITH_MILLIS, Locale.ROOT); - simpleDateFormat.setTimeZone(UTC_TIMEZONE); - return simpleDateFormat; - } - }; - - private static final @NotNull ThreadLocal SDF_ISO_FORMAT_UTC = - new ThreadLocal() { - @Override - protected SimpleDateFormat initialValue() { - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(ISO_FORMAT, Locale.ROOT); - simpleDateFormat.setTimeZone(UTC_TIMEZONE); - return simpleDateFormat; - } - }; - private DateUtils() {} /** @@ -66,14 +41,8 @@ private DateUtils() {} public static @NotNull Date getDateTime(final @NotNull String timestamp) throws IllegalArgumentException { try { - return SDF_ISO_FORMAT_WITH_MILLIS_UTC.get().parse(timestamp); + return ISO8601Utils.parse(timestamp, new ParsePosition(0)); } catch (ParseException e) { - try { - // to keep compatibility with older envelopes - return SDF_ISO_FORMAT_UTC.get().parse(timestamp); - } catch (ParseException ignored) { - // invalid timestamp format - } throw new IllegalArgumentException("timestamp is not ISO format " + timestamp); } } @@ -102,8 +71,7 @@ private DateUtils() {} * @return the UTC/ISO 8601 timestamp */ public static @NotNull String getTimestamp(final @NotNull Date date) { - final DateFormat df = SDF_ISO_FORMAT_WITH_MILLIS_UTC.get(); - return df.format(date); + return ISO8601Utils.format(date, true); } /** From 3396d7336f4ab1b2aa0373740a31e971e9910328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Thu, 9 Dec 2021 16:57:03 +0100 Subject: [PATCH 4/7] api dump --- sentry/api/sentry.api | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index c07e9245c7..1ce42a6550 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -2652,6 +2652,14 @@ public class io/sentry/vendor/Base64 { public static fun encodeToString ([BIII)Ljava/lang/String; } +public class io/sentry/vendor/gson/internal/bind/util/ISO8601Utils { + public fun ()V + public static fun format (Ljava/util/Date;)Ljava/lang/String; + public static fun format (Ljava/util/Date;Z)Ljava/lang/String; + public static fun format (Ljava/util/Date;ZLjava/util/TimeZone;)Ljava/lang/String; + public static fun parse (Ljava/lang/String;Ljava/text/ParsePosition;)Ljava/util/Date; +} + public class io/sentry/vendor/gson/stream/JsonReader : java/io/Closeable { public fun (Ljava/io/Reader;)V public fun beginArray ()V From a350b1dd9c9e8d77ee2147a2314df471e44560c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Wed, 15 Dec 2021 14:03:11 +0100 Subject: [PATCH 5/7] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index faa763d08c..bfc563d2f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* Ref: Simplify DateUtils with ISO8601Utils (#1837) + ## 6.0.0-alpha.1 * Feat: Use float instead of Date for protocol types for higher precision (#1737) From aac65a13643e42c2fb4edac531f7dcf0a427a24a Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 18 Jan 2022 09:12:08 -0300 Subject: [PATCH 6/7] use shared timezone --- sentry/api/sentry.api | 2 ++ sentry/src/main/java/io/sentry/DateUtils.java | 11 ++++------- .../vendor/gson/internal/bind/util/ISO8601Utils.java | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index de92d94a93..0f39e55695 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -1932,6 +1932,7 @@ public final class io/sentry/protocol/Device$JsonKeys { public static final field FREE_STORAGE Ljava/lang/String; public static final field ID Ljava/lang/String; public static final field LANGUAGE Ljava/lang/String; + public static final field LOCALE Ljava/lang/String; public static final field LOW_MEMORY Ljava/lang/String; public static final field MANUFACTURER Ljava/lang/String; public static final field MEMORY_SIZE Ljava/lang/String; @@ -2709,6 +2710,7 @@ public class io/sentry/vendor/Base64 { } public class io/sentry/vendor/gson/internal/bind/util/ISO8601Utils { + public static final field TIMEZONE_UTC Ljava/util/TimeZone; public fun ()V public static fun format (Ljava/util/Date;)Ljava/lang/String; public static fun format (Ljava/util/Date;Z)Ljava/lang/String; diff --git a/sentry/src/main/java/io/sentry/DateUtils.java b/sentry/src/main/java/io/sentry/DateUtils.java index 01d989b85b..e99d6b9f68 100644 --- a/sentry/src/main/java/io/sentry/DateUtils.java +++ b/sentry/src/main/java/io/sentry/DateUtils.java @@ -1,5 +1,7 @@ package io.sentry; +import static io.sentry.vendor.gson.internal.bind.util.ISO8601Utils.TIMEZONE_UTC; + import io.sentry.vendor.gson.internal.bind.util.ISO8601Utils; import java.math.BigDecimal; import java.math.RoundingMode; @@ -7,17 +9,12 @@ import java.text.ParsePosition; import java.util.Calendar; import java.util.Date; -import java.util.TimeZone; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; /** Utilities to deal with dates */ @ApiStatus.Internal public final class DateUtils { - private static final String UTC = "UTC"; - - // if UTC is not found, it fallback to "GMT" which is UTC equivalent - private static final @NotNull TimeZone UTC_TIMEZONE = TimeZone.getTimeZone(UTC); private DateUtils() {} @@ -28,7 +25,7 @@ private DateUtils() {} */ @SuppressWarnings("JdkObsolete") public static @NotNull Date getCurrentDateTime() { - final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE); + final Calendar calendar = Calendar.getInstance(TIMEZONE_UTC); return calendar.getTime(); } @@ -81,7 +78,7 @@ private DateUtils() {} * @return the UTC Date */ public static @NotNull Date getDateTime(final long millis) { - final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE); + final Calendar calendar = Calendar.getInstance(TIMEZONE_UTC); calendar.setTimeInMillis(millis); return calendar.getTime(); } diff --git a/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java b/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java index 2a0fd05e95..b00aff52c6 100644 --- a/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java +++ b/sentry/src/main/java/io/sentry/vendor/gson/internal/bind/util/ISO8601Utils.java @@ -36,7 +36,7 @@ public class ISO8601Utils * * @since 2.7 */ - private static final TimeZone TIMEZONE_UTC = TimeZone.getTimeZone(UTC_ID); + public static final TimeZone TIMEZONE_UTC = TimeZone.getTimeZone(UTC_ID); /* /********************************************************** From 48c3aee780e584705bbbcaa10f179282b8251fce Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 18 Jan 2022 09:27:11 -0300 Subject: [PATCH 7/7] fix javadocs --- .../io/sentry/vendor/gson/stream/JsonReader.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sentry/src/main/java/io/sentry/vendor/gson/stream/JsonReader.java b/sentry/src/main/java/io/sentry/vendor/gson/stream/JsonReader.java index 859eb0bfb4..15a19fa95d 100644 --- a/sentry/src/main/java/io/sentry/vendor/gson/stream/JsonReader.java +++ b/sentry/src/main/java/io/sentry/vendor/gson/stream/JsonReader.java @@ -774,7 +774,7 @@ private boolean isLiteral(char c) throws IOException { } /** - * Returns the next token, a {@link com.google.gson.stream.JsonToken#NAME property name}, and + * Returns the next token, a {@link JsonToken#NAME property name}, and * consumes it. * * @throws java.io.IOException if the next token in the stream is not a property @@ -801,7 +801,7 @@ public String nextName() throws IOException { } /** - * Returns the {@link com.google.gson.stream.JsonToken#STRING string} value of the next token, + * Returns the {@link JsonToken#STRING string} value of the next token, * consuming it. If the next token is a number, this method will return its * string form. * @@ -837,7 +837,7 @@ public String nextString() throws IOException { } /** - * Returns the {@link com.google.gson.stream.JsonToken#BOOLEAN boolean} value of the next token, + * Returns the {@link JsonToken#BOOLEAN boolean} value of the next token, * consuming it. * * @throws IllegalStateException if the next token is not a boolean or if @@ -881,7 +881,7 @@ public void nextNull() throws IOException { } /** - * Returns the {@link com.google.gson.stream.JsonToken#NUMBER double} value of the next token, + * Returns the {@link JsonToken#NUMBER double} value of the next token, * consuming it. If the next token is a string, this method will attempt to * parse it as a double using {@link Double#parseDouble(String)}. * @@ -925,7 +925,7 @@ public double nextDouble() throws IOException { } /** - * Returns the {@link com.google.gson.stream.JsonToken#NUMBER long} value of the next token, + * Returns the {@link JsonToken#NUMBER long} value of the next token, * consuming it. If the next token is a string, this method will attempt to * parse it as a long. If the next token's numeric value cannot be exactly * represented by a Java {@code long}, this method throws. @@ -1157,7 +1157,7 @@ private void skipUnquotedValue() throws IOException { } /** - * Returns the {@link com.google.gson.stream.JsonToken#NUMBER int} value of the next token, + * Returns the {@link JsonToken#NUMBER int} value of the next token, * consuming it. If the next token is a string, this method will attempt to * parse it as an int. If the next token's numeric value cannot be exactly * represented by a Java {@code int}, this method throws.