Replace long time_ms with Instant and Duration, respectively.

Fixes #561.
This commit is contained in:
Dennis Guse
2021-01-09 13:27:14 +01:00
parent 3bbcbfe202
commit e990b413cd
47 changed files with 442 additions and 434 deletions
@@ -4,13 +4,16 @@ import android.content.Context;
import androidx.annotation.Nullable;
import java.time.Duration;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
public class AnnouncementUtils {
private AnnouncementUtils() {}
private AnnouncementUtils() {
}
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category, @Nullable IntervalStatistics.Interval currentInterval) {
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
@@ -41,11 +44,11 @@ public class AnnouncementUtils {
} else {
double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime;
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
long time = Math.round(timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
Duration time = Duration.ofMillis((long) (timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS));
rate = context.getString(paceId, getAnnounceTime(context, time));
double currentTimePerDistance = currentDistancePerTime == 0 ? 0.0 : 1 / currentDistancePerTime;
long currentTime = Math.round(currentTimePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
Duration currentTime = Duration.ofMillis((long) (currentTimePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS));
currentRate = context.getString(paceId, getAnnounceTime(context, currentTime));
currentRateMsg = context.getString(R.string.voice_pace_lap, currentRate);
}
@@ -58,23 +61,25 @@ public class AnnouncementUtils {
return context.getString(R.string.voice_template, totalDistance, getAnnounceTime(context, trackStatistics.getMovingTime()), rate) + currentRateMsg;
}
private static String getAnnounceTime(Context context, long time) {
int[] parts = StringUtils.getTimeParts(time);
String seconds = context.getResources()
.getQuantityString(R.plurals.voiceSeconds, parts[0], parts[0]);
String minutes = context.getResources()
.getQuantityString(R.plurals.voiceMinutes, parts[1], parts[1]);
String hours = context.getResources()
.getQuantityString(R.plurals.voiceHours, parts[2], parts[2]);
StringBuilder sb = new StringBuilder();
if (parts[2] != 0) {
sb.append(hours);
sb.append(" ");
//TODO We might need to localize this using strings.xml if order is relevant.
private static String getAnnounceTime(Context context, Duration duration) {
String result = "";
int hours = (int) (duration.getSeconds() / (60 * 60));
int minutes = (int) (duration.getSeconds() / 60);
int seconds = (int) (duration.getSeconds() % 60);
if (hours != 0) {
String hoursText = context.getResources()
.getQuantityString(R.plurals.voiceHours, hours, hours);
result += hoursText + " ";
}
sb.append(minutes);
sb.append(" ");
sb.append(seconds);
return sb.toString();
String minutesText = context.getResources()
.getQuantityString(R.plurals.voiceMinutes, minutes, minutes);
String secondsText = context.getResources()
.getQuantityString(R.plurals.voiceSeconds, seconds, seconds);
return result + minutesText + " " + secondsText;
}
/**
@@ -17,6 +17,9 @@ package de.dennisguse.opentracks.util;
import android.location.Location;
import java.time.Duration;
import java.time.Instant;
import de.dennisguse.opentracks.content.data.TrackPoint;
/**
@@ -28,8 +31,7 @@ public class LocationUtils {
private static final String TAG = LocationUtils.class.getSimpleName();
// 1 minute in milliseconds
private static final long MAX_LOCATION_AGE_MS = (long) (UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS);
private static final Duration MAX_LOCATION_AGE = Duration.ofMinutes(1);
private LocationUtils() {
}
@@ -48,6 +50,8 @@ public class LocationUtils {
}
public static boolean isTrackPointOld(TrackPoint trackPoint) {
return System.currentTimeMillis() - trackPoint.getTime() > MAX_LOCATION_AGE_MS;
return Duration.between(trackPoint.getTime(), Instant.now())
.minus(MAX_LOCATION_AGE)
.isNegative();
}
}
@@ -22,8 +22,11 @@ import android.text.format.DateUtils;
import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
@@ -50,41 +53,32 @@ public class StringUtils {
}
/**
* Formats the date and time_ms based on user's phone date/time_ms preferences.
*
* @param context the context
* @param time_ms the time_ms in milliseconds
* Formats the date and time based on user's phone date/time preferences.
*/
public static String formatDateTime(Context context, long time_ms) {
return DateUtils.formatDateTime(context, time_ms, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE)
+ " " + DateUtils.formatDateTime(context, time_ms, DateUtils.FORMAT_SHOW_TIME);
public static String formatDateTime(Context context, Instant time) {
return DateUtils.formatDateTime(context, time.toEpochMilli(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE)
+ " " + DateUtils.formatDateTime(context, time.toEpochMilli(), DateUtils.FORMAT_SHOW_TIME);
}
/**
* Formats the time using the ISO 8601 date time_ms format with fractional seconds in UTC time zone.
*
* @param time_ms the time in milliseconds
* Formats the time using the ISO 8601 date time format with fractional seconds in UTC time zone.
*/
public static String formatDateTimeIso8601(long time_ms) {
return Instant.ofEpochMilli(time_ms).toString();
public static String formatDateTimeIso8601(@NonNull Instant time) {
return time.toString();
}
/**
* Formats the elapsed timed in the form "MM:SS" or "H:MM:SS".
*
* @param time_ms the time in milliseconds
*/
public static String formatElapsedTime(long time_ms) {
return DateUtils.formatElapsedTime((long) (time_ms * UnitConversions.MS_TO_S));
public static String formatElapsedTime(@NonNull Duration time) {
return DateUtils.formatElapsedTime(time.getSeconds());
}
/**
* Formats the elapsed time in the form "H:MM:SS".
*
* @param time_ms the time in milliseconds
*/
public static String formatElapsedTimeWithHour(long time_ms) {
String value = formatElapsedTime(time_ms);
public static String formatElapsedTimeWithHour(@NonNull Duration time) {
String value = formatElapsedTime(time);
return TextUtils.split(value, ":").length == 2 ? "0:" + value : value;
}
@@ -289,45 +283,20 @@ public class StringUtils {
*
* @param xmlDateTime the XML date time string
*/
public static long parseTime(String xmlDateTime) {
public static Instant parseTime(String xmlDateTime) {
try {
TemporalAccessor t = DateTimeFormatter.ISO_DATE_TIME.parseBest(xmlDateTime, ZonedDateTime::from, LocalDateTime::from);
if (t instanceof LocalDateTime) {
Log.w(TAG, "Date does not contain timezone information: using UTC.");
t = ((LocalDateTime) t).atZone(ZoneOffset.UTC);
}
return Instant.from(t).toEpochMilli();
return Instant.from(t);
} catch (Exception e) {
Log.e(TAG, "Invalid XML dateTime value");
throw e;
}
}
/**
* Gets the time as an array of three integers.
* Index 0 contains the number of seconds, index 1 contains the number of minutes, and index 2 contains the number of hours.
*
* @param time the time in milliseconds
* @return an array of 3 elements.
*/
public static int[] getTimeParts(long time) {
if (time < 0) {
int[] parts = getTimeParts(time * -1);
parts[0] *= -1;
parts[1] *= -1;
parts[2] *= -1;
return parts;
}
int[] parts = new int[3];
long seconds = (long) (time * UnitConversions.MS_TO_S);
parts[0] = (int) (seconds % 60);
int minutes = (int) (seconds / 60);
parts[1] = minutes % 60;
parts[2] = minutes / 60;
return parts;
}
/**
* Gets the frequency display options.
*
@@ -21,6 +21,7 @@ import android.content.Context;
import androidx.annotation.VisibleForTesting;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Locale;
import de.dennisguse.opentracks.R;
@@ -40,20 +41,13 @@ public class TrackNameUtils {
private TrackNameUtils() {
}
/**
* Gets the track name.
*
* @param context the context
* @param trackId the track id
* @param startTime the track start time
*/
public static String getTrackName(Context context, Track.Id trackId, long startTime) {
public static String getTrackName(Context context, Track.Id trackId, Instant startTime) {
String trackName = PreferencesUtils.getString(context, R.string.track_name_key, context.getString(R.string.track_name_default));
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
return StringUtils.formatDateTime(context, startTime);
} else if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_iso_8601_value))) {
return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime);
return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime.toEpochMilli());
} else {
return context.getString(R.string.track_name_format, trackId.getId());
}
@@ -18,22 +18,6 @@ public class TrackPointUtils {
return trackPoint.hasSpeed() && trackPoint.getSpeed() >= MAX_NO_MOVEMENT_SPEED;
}
public static boolean equalTime(TrackPoint t1, TrackPoint t2) {
if (t1 == null || t2 == null) {
return false;
}
return t1.getTime() == t2.getTime();
}
public static boolean after(TrackPoint t1, TrackPoint t2) {
if (t1 == null || t2 == null) {
return false;
}
return t1.getTime() > t2.getTime();
}
/**
* Is accuracy better than threshold?
*/