diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index d6ccd3acdb..9c2b6c68ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -87,6 +87,7 @@ public class RuneLite private static final File LOG_FILE = new File(LOGS_DIR, "client.log"); private static final RuneLiteProperties PROPERTIES = new RuneLiteProperties(); public static boolean allowPrivateServer = false; + public static final Locale SYSTEM_LOCALE = Locale.getDefault(); @Getter private static Injector injector; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java index 47740a8b17..434652fdb8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TabContentPanel.java @@ -30,6 +30,7 @@ import java.time.format.TextStyle; import java.time.temporal.ChronoUnit; import java.util.Locale; import javax.swing.JPanel; +import net.runelite.client.util.StackFormatter; public abstract class TabContentPanel extends JPanel { @@ -80,7 +81,8 @@ public abstract class TabContentPanel extends JPanel { sb.append(endTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())).append(" "); } - sb.append(String.format("at %d:%02d", endTime.getHour(), endTime.getMinute())); + + sb.append("at ").append(StackFormatter.getPlatformTimeStringFromLocalDateTime(endTime)); return sb.toString(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/util/StackFormatter.java b/runelite-client/src/main/java/net/runelite/client/util/StackFormatter.java index 38a8669244..006e024223 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/StackFormatter.java +++ b/runelite-client/src/main/java/net/runelite/client/util/StackFormatter.java @@ -28,9 +28,13 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.text.ParseException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; +import net.runelite.client.RuneLite; /** * A set of utility functions to use when @@ -69,6 +73,34 @@ public class StackFormatter DecimalFormatSymbols.getInstance(Locale.ENGLISH) ); + /** + * Attempts to call the platform to get a localized time string based on + * the users preferences. Falls back on using locale default if it is on a + * platform that has no consistent way of obtaining this information. + * + * @param localDateTime The LocalDateTime object to format as a string + * @return The formatted string. + */ + public static String getPlatformTimeStringFromLocalDateTime(LocalDateTime localDateTime) + { + if (OSType.getOSType() == OSType.Windows) + { + return WinApi.getTimeFormatString(localDateTime); + } + return StackFormatter.getLocalizedDateTimeFormatter(FormatStyle.SHORT).format(localDateTime.toLocalTime()); + } + + /** + * Get a localized DateTimeFormatter for use. + * + * @param formatStyle The format style to use for the formatter + * @return The localized DateTimeFormatter + */ + public static DateTimeFormatter getLocalizedDateTimeFormatter(FormatStyle formatStyle) + { + return DateTimeFormatter.ofLocalizedTime(formatStyle).withLocale(RuneLite.SYSTEM_LOCALE); + } + /** * Convert a quantity to a nicely formatted stack size. * See the StackFormatterTest to see expected output. diff --git a/runelite-client/src/main/java/net/runelite/client/util/WinApi.java b/runelite-client/src/main/java/net/runelite/client/util/WinApi.java new file mode 100644 index 0000000000..430998c7a3 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/util/WinApi.java @@ -0,0 +1,38 @@ +package net.runelite.client.util; + +import com.sun.jna.Native; +import com.sun.jna.WString; +import com.sun.jna.platform.win32.WinBase; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.win32.StdCallLibrary; +import java.time.LocalDateTime; + +interface Kernel32 extends StdCallLibrary +{ + int TIME_NOSECONDS = 0x00000002; + + int GetTimeFormatEx( + WString lpLocaleName, WinDef.DWORD dwFlags, WinBase.SYSTEMTIME lpTime, + WString lpFormat, char[] lpTimeStr, int cchTime); + +} + +public class WinApi +{ + static Kernel32 kernel32 = Native.loadLibrary("kernel32", Kernel32.class); + + public static String getTimeFormatString(LocalDateTime localDateTime) + { + char[] lpTimeStr = new char[80]; + WinDef.DWORD dwFlags = new WinDef.DWORD(Kernel32.TIME_NOSECONDS); + + WinBase.SYSTEMTIME time = new WinBase.SYSTEMTIME(); + time.wHour = (short) localDateTime.getHour(); + time.wMinute = (short) localDateTime.getMinute(); + time.wSecond = (short) localDateTime.getSecond(); + time.wMilliseconds = 0; + + kernel32.GetTimeFormatEx(null, dwFlags, time, null, lpTimeStr, 80); + return new String(lpTimeStr); + } +}