1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.gui.layer.geoimage;
|
---|
3 |
|
---|
4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
5 |
|
---|
6 | import java.text.ParseException;
|
---|
7 | import java.util.Locale;
|
---|
8 | import java.util.Objects;
|
---|
9 | import java.util.concurrent.TimeUnit;
|
---|
10 |
|
---|
11 | import org.openstreetmap.josm.tools.JosmDecimalFormatSymbolsProvider;
|
---|
12 | import org.openstreetmap.josm.tools.Pair;
|
---|
13 |
|
---|
14 | /**
|
---|
15 | * Time offset of GPX correlation.
|
---|
16 | * @since 11914 (extracted from {@link CorrelateGpxWithImages})
|
---|
17 | */
|
---|
18 | public final class Offset {
|
---|
19 |
|
---|
20 | static final Offset ZERO = new Offset(0);
|
---|
21 | private final long milliseconds;
|
---|
22 |
|
---|
23 | private Offset(long milliseconds) {
|
---|
24 | this.milliseconds = milliseconds;
|
---|
25 | }
|
---|
26 |
|
---|
27 | static Offset milliseconds(long milliseconds) {
|
---|
28 | return new Offset(milliseconds);
|
---|
29 | }
|
---|
30 |
|
---|
31 | static Offset seconds(long seconds) {
|
---|
32 | return new Offset(1000 * seconds);
|
---|
33 | }
|
---|
34 |
|
---|
35 | long getMilliseconds() {
|
---|
36 | return milliseconds;
|
---|
37 | }
|
---|
38 |
|
---|
39 | long getSeconds() {
|
---|
40 | return milliseconds / 1000;
|
---|
41 | }
|
---|
42 |
|
---|
43 | String formatOffset() {
|
---|
44 | if (milliseconds % 1000 == 0) {
|
---|
45 | return Long.toString(milliseconds / 1000);
|
---|
46 | } else if (milliseconds % 100 == 0) {
|
---|
47 | return String.format(Locale.ENGLISH, "%.1f", milliseconds / 1000.);
|
---|
48 | } else {
|
---|
49 | return String.format(Locale.ENGLISH, "%.3f", milliseconds / 1000.);
|
---|
50 | }
|
---|
51 | }
|
---|
52 |
|
---|
53 | static Offset parseOffset(String offset) throws ParseException {
|
---|
54 | String error = tr("Error while parsing offset.\nExpected format: {0}", "number");
|
---|
55 |
|
---|
56 | if (!offset.isEmpty()) {
|
---|
57 | try {
|
---|
58 | if (offset.startsWith("+")) {
|
---|
59 | offset = offset.substring(1);
|
---|
60 | }
|
---|
61 | return Offset.milliseconds(Math.round(JosmDecimalFormatSymbolsProvider.parseDouble(offset) * 1000));
|
---|
62 | } catch (NumberFormatException nfe) {
|
---|
63 | throw (ParseException) new ParseException(error, 0).initCause(nfe);
|
---|
64 | }
|
---|
65 | } else {
|
---|
66 | return Offset.ZERO;
|
---|
67 | }
|
---|
68 | }
|
---|
69 |
|
---|
70 | int getDayOffset() {
|
---|
71 | // Find day difference
|
---|
72 | return (int) Math.round(((double) getMilliseconds()) / TimeUnit.DAYS.toMillis(1));
|
---|
73 | }
|
---|
74 |
|
---|
75 | Offset withoutDayOffset() {
|
---|
76 | return milliseconds(getMilliseconds() - TimeUnit.DAYS.toMillis(getDayOffset()));
|
---|
77 | }
|
---|
78 |
|
---|
79 | Pair<Timezone, Offset> splitOutTimezone() {
|
---|
80 | // In hours
|
---|
81 | final double tz = ((double) withoutDayOffset().getSeconds()) / TimeUnit.HOURS.toSeconds(1);
|
---|
82 |
|
---|
83 | // Due to imprecise clocks we might get a "+3:28" timezone, which should obviously be 3:30 with
|
---|
84 | // -2 minutes offset. This determines the real timezone and finds offset.
|
---|
85 | final double timezone = (double) Math.round(tz * 2) / 2; // hours, rounded to one decimal place
|
---|
86 | final long delta = Math.round(getMilliseconds() - timezone * TimeUnit.HOURS.toMillis(1));
|
---|
87 | return Pair.create(new Timezone(timezone), Offset.milliseconds(delta));
|
---|
88 | }
|
---|
89 |
|
---|
90 | @Override
|
---|
91 | public boolean equals(Object o) {
|
---|
92 | if (this == o) return true;
|
---|
93 | if (!(o instanceof Offset)) return false;
|
---|
94 | Offset offset = (Offset) o;
|
---|
95 | return milliseconds == offset.milliseconds;
|
---|
96 | }
|
---|
97 |
|
---|
98 | @Override
|
---|
99 | public int hashCode() {
|
---|
100 | return Objects.hash(milliseconds);
|
---|
101 | }
|
---|
102 | }
|
---|