aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAaron <51387595+AzureAaron@users.noreply.github.com>2025-02-14 21:12:32 -0500
committerGitHub <noreply@github.com>2025-02-15 10:12:32 +0800
commit285085d01f1fa5ffe55d88975f6155a486118aed (patch)
tree861e74f11277fa15d85e756ff6fd0749cbeeded2 /src
parent2270b4925aa1f7c4e64371c85e8354bb2f3fdb55 (diff)
downloadSkyblocker-285085d01f1fa5ffe55d88975f6155a486118aed.tar.gz
Skyblocker-285085d01f1fa5ffe55d88975f6155a486118aed.tar.bz2
Skyblocker-285085d01f1fa5ffe55d88975f6155a486118aed.zip
Formatters (#1151)
* Formatters * java yap --------- Co-authored-by: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Formatters.java88
-rw-r--r--src/test/java/de/hysky/skyblocker/utils/FormattersTest.java61
2 files changed, 149 insertions, 0 deletions
diff --git a/src/main/java/de/hysky/skyblocker/utils/Formatters.java b/src/main/java/de/hysky/skyblocker/utils/Formatters.java
new file mode 100644
index 00000000..539f9d67
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/Formatters.java
@@ -0,0 +1,88 @@
+package de.hysky.skyblocker.utils;
+
+import java.text.NumberFormat;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+import com.ibm.icu.text.DateTimePatternGenerator;
+
+import ca.weblite.objc.Client;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.util.Util;
+
+/**
+ * Provides useful constants for formatting numbers and dates. If you need to make slight tweaks to a formatter
+ * then {@link NumberFormat#clone()} the object and modify it as needed.
+ */
+public class Formatters {
+ /**
+ * Formats numbers as integers with commas.
+ *
+ * Example: 100,000,000
+ */
+ public static final NumberFormat INTEGER_NUMBERS = NumberFormat.getIntegerInstance(Locale.US);
+ /**
+ * Formats numbers as floats with up to two digits of precision.
+ *
+ * Example: 100,000.15
+ */
+ public static final NumberFormat DOUBLE_NUMBERS = Util.make(NumberFormat.getInstance(Locale.US), nf -> nf.setMaximumFractionDigits(2));
+ /**
+ * Formats numbers as floats with up to one digit of precision.
+ *
+ * Example: 100,000.1
+ */
+ public static final NumberFormat FLOAT_NUMBERS = Util.make(NumberFormat.getInstance(Locale.US), nf -> nf.setMaximumFractionDigits(1));
+ /**
+ * Formats integer numbers in a short format.
+ *
+ * Examples: 10B, 1M, and 5K.
+ */
+ public static final NumberFormat SHORT_INTEGER_NUMBERS = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
+ /**
+ * Formats float numbers in a short format.
+ *
+ * Examples: 17.3B, 1.5M, and 10.8K.
+ */
+ public static final NumberFormat SHORT_FLOAT_NUMBERS = Util.make(NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT), nf -> nf.setMinimumFractionDigits(1));
+ /**
+ * Formats dates to a standard format.
+ *
+ * Examples: Thu Jan 30 2025 2:00:10 PM, Thu Jan 30 2025 14:00:10
+ */
+ public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("E MMM d yyyy " + getTimeFormat(), Locale.US).withZone(ZoneId.systemDefault());
+
+ /**
+ * Returns the formatting for the time, always returns 12 hour in development environments for testing purposes.
+ */
+ private static String getTimeFormat() {
+ return is12HourClock() || FabricLoader.getInstance().isDevelopmentEnvironment() ? "h:mm:ss a" : "HH:mm:ss";
+ }
+
+ /**
+ * Determines whether to use the 12 or 24 hour clock for formatting time.<br><br>
+ *
+ * On macOS this reads the preference for the system clock's time format which accounts for whether a user
+ * chooses 12 or 24 hour time in the System Settings.<br><br>
+ *
+ * On other platforms, the time format follows the default for the user's current locale.
+ *
+ * @see <a href="https://developer.apple.com/documentation/foundation/nsdateformatter/1408112-dateformatfromtemplate?language=objc">NSDateFormatter</a>
+ * @see <a href="https://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Field_Symbol_Table">Unicode Locale Data Markup Language (LDML)</a>
+ */
+ private static boolean is12HourClock() {
+ //The j formatting template returns the preferred formatting for the time
+ //If the format contains a (am/pm pattern) then the preference is to use the 12 hour clock, otherwise its the 24 hour clock
+ if (MinecraftClient.IS_SYSTEM_MAC) {
+ Object locale = Client.getInstance().send("NSLocale", "currentLocale");
+ String timeFormat = (String) Client.getInstance().send("NSDateFormatter", "dateFormatFromTemplate:options:locale:", "j", 0, locale);
+
+ return timeFormat.contains("a");
+ } else {
+ return DateTimePatternGenerator.getInstance(Locale.getDefault()).getBestPattern("j").contains("a");
+ }
+ }
+}
+
diff --git a/src/test/java/de/hysky/skyblocker/utils/FormattersTest.java b/src/test/java/de/hysky/skyblocker/utils/FormattersTest.java
new file mode 100644
index 00000000..a564eb06
--- /dev/null
+++ b/src/test/java/de/hysky/skyblocker/utils/FormattersTest.java
@@ -0,0 +1,61 @@
+package de.hysky.skyblocker.utils;
+
+import java.time.Instant;
+import java.util.TimeZone;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class FormattersTest {
+
+ @BeforeAll
+ public static void setupEnvironment() {
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+ }
+
+ @Test
+ void testIntegerNumbers() {
+ Assertions.assertEquals("100,000,000", Formatters.INTEGER_NUMBERS.format(100_000_000));
+ Assertions.assertEquals("99,999,999", Formatters.INTEGER_NUMBERS.format(99_999_999.4));
+ Assertions.assertEquals("88,888,888", Formatters.INTEGER_NUMBERS.format(88_888_888.5)); //Half even rounding
+ Assertions.assertEquals("77,777,777", Formatters.INTEGER_NUMBERS.format(77_777_776.7));
+ }
+
+ @Test
+ void testDoubleNumbers() {
+ Assertions.assertEquals("100,000,000.15", Formatters.DOUBLE_NUMBERS.format(100_000_000.152341));
+ Assertions.assertEquals("99,999,999.98", Formatters.DOUBLE_NUMBERS.format(99_999_999.978));
+ }
+
+ @Test
+ void testFloatNumbers() {
+ Assertions.assertEquals("100,000,000.8", Formatters.FLOAT_NUMBERS.format(100_000_000.7834));
+ Assertions.assertEquals("99,999,999.8", Formatters.FLOAT_NUMBERS.format(99_999_999.84243));
+ }
+
+ @Test
+ void testShortIntegerNumbers() {
+ Assertions.assertEquals("16B", Formatters.SHORT_INTEGER_NUMBERS.format(15_500_000_000L));
+ Assertions.assertEquals("10M", Formatters.SHORT_INTEGER_NUMBERS.format(10_200_000));
+ Assertions.assertEquals("5K", Formatters.SHORT_INTEGER_NUMBERS.format(5_000));
+ }
+
+ @Test
+ void testShortFloatNumbers() {
+ Assertions.assertEquals("14.5B", Formatters.SHORT_FLOAT_NUMBERS.format(14_500_000_000L));
+ Assertions.assertEquals("8.3M", Formatters.SHORT_FLOAT_NUMBERS.format(8_300_000));
+ Assertions.assertEquals("24.7K", Formatters.SHORT_FLOAT_NUMBERS.format(24_740));
+ }
+
+ @Test
+ void testDates() {
+ long Thu_Jan_30th_2025_at_4_10_00_PM = 1738253400000L;
+ long Fri_Jan_31st_2025_at_11_11_00_AM = 1738321860000L;
+ long Sat_Feb_1st_2025_at_12_00_01_AM = 1738368001000L;
+
+ Assertions.assertEquals("Thu Jan 30 2025 4:10:00 PM", Formatters.DATE_FORMATTER.format(Instant.ofEpochMilli(Thu_Jan_30th_2025_at_4_10_00_PM)));
+ Assertions.assertEquals("Fri Jan 31 2025 11:11:00 AM", Formatters.DATE_FORMATTER.format(Instant.ofEpochMilli(Fri_Jan_31st_2025_at_11_11_00_AM)));
+ Assertions.assertEquals("Sat Feb 1 2025 12:00:01 AM", Formatters.DATE_FORMATTER.format(Instant.ofEpochMilli(Sat_Feb_1st_2025_at_12_00_01_AM)));
+ }
+}