summaryrefslogtreecommitdiffstats
path: root/Essentials/src/net/ess3/utils/DescParseTickFormat.java
blob: a0ec8094f2280d64b43e5e095f1927646f61fc1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
package net.ess3.utils;

import java.text.SimpleDateFormat;
import java.util.*;
import static net.ess3.I18n._;


/**
 * This utility class is used for converting between the ingame time in ticks to ingame time as a friendly string. Note
 * that the time is INGAME.
 *
 * http://www.minecraftwiki.net/wiki/Day/night_cycle
 *
 * @author Olof Larsson
 */
public final class DescParseTickFormat
{
	public static final Map<String, Integer> nameToTicks = new LinkedHashMap<String, Integer>();
	public static final Set<String> resetAliases = new HashSet<String>();
	public static final int ticksAtMidnight = 18000;
	public static final int ticksPerDay = 24000;
	public static final int ticksPerHour = 1000;
	public static final double ticksPerMinute = 1000d / 60d;
	public static final double ticksPerSecond = 1000d / 60d / 60d;
	private static final SimpleDateFormat SDFTwentyFour = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
	private static final SimpleDateFormat SDFTwelve = new SimpleDateFormat("h:mmaa", Locale.ENGLISH);

	static
	{
		SDFTwentyFour.setTimeZone(TimeZone.getTimeZone("GMT"));
		SDFTwelve.setTimeZone(TimeZone.getTimeZone("GMT"));

		nameToTicks.put("sunrise", 23000);
		nameToTicks.put("dawn", 23000);

		nameToTicks.put("daystart", 0);
		nameToTicks.put("day", 0);

		nameToTicks.put("morning", 1000);

		nameToTicks.put("midday", 6000);
		nameToTicks.put("noon", 6000);

		nameToTicks.put("afternoon", 9000);

		nameToTicks.put("sunset", 12000);
		nameToTicks.put("dusk", 12000);
		nameToTicks.put("sundown", 12000);
		nameToTicks.put("nightfall", 12000);

		nameToTicks.put("nightstart", 14000);
		nameToTicks.put("night", 14000);

		nameToTicks.put("midnight", 18000);

		resetAliases.add("reset");
		resetAliases.add("normal");
		resetAliases.add("default");
	}

	private DescParseTickFormat()
	{
	}

	// ============================================
	// PARSE. From describing String to int
	// --------------------------------------------
	public static long parse(String desc) throws NumberFormatException
	{
		// Only look at alphanumeric and lowercase and : for 24:00
		desc = desc.toLowerCase(Locale.ENGLISH).replaceAll("[^A-Za-z0-9:]", "");

		// Detect ticks format
		try
		{
			return parseTicks(desc);
		}
		catch (Exception e)
		{
		}

		// Detect 24-hour format
		try
		{
			return parse24(desc);
		}
		catch (Exception e)
		{
		}

		// Detect 12-hour format
		try
		{
			return parse12(desc);
		}
		catch (Exception e)
		{
		}

		// Detect aliases
		try
		{
			return parseAlias(desc);
		}
		catch (Exception e)
		{
		}

		// Well we failed to understand...
		throw new NumberFormatException();
	}

	public static long parseTicks(String desc) throws NumberFormatException
	{
		if (!desc.matches("^[0-9]+ti?c?k?s?$"))
		{
			throw new NumberFormatException();
		}

		desc = desc.replaceAll("[^0-9]", "");

		return Long.parseLong(desc) % 24000;
	}

	public static long parse24(String desc) throws NumberFormatException
	{
		if (!desc.matches("^[0-9]{2}[^0-9]?[0-9]{2}$"))
		{
			throw new NumberFormatException();
		}

		desc = desc.toLowerCase(Locale.ENGLISH).replaceAll("[^0-9]", "");

		if (desc.length() != 4)
		{
			throw new NumberFormatException();
		}

		final int hours = Integer.parseInt(desc.substring(0, 2));
		final int minutes = Integer.parseInt(desc.substring(2, 4));

		return hoursMinutesToTicks(hours, minutes);
	}

	public static long parse12(String desc) throws NumberFormatException
	{
		if (!desc.matches("^[0-9]{1,2}([^0-9]?[0-9]{2})?(pm|am)$"))
		{
			throw new NumberFormatException();
		}

		int hours = 0;
		int minutes = 0;

		desc = desc.toLowerCase(Locale.ENGLISH);
		String parsetime = desc.replaceAll("[^0-9]", "");

		if (parsetime.length() > 4)
		{
			throw new NumberFormatException();
		}

		if (parsetime.length() == 4)
		{
			hours += Integer.parseInt(parsetime.substring(0, 2));
			minutes += Integer.parseInt(parsetime.substring(2, 4));
		}
		else if (parsetime.length() == 3)
		{
			hours += Integer.parseInt(parsetime.substring(0, 1));
			minutes += Integer.parseInt(parsetime.substring(1, 3));
		}
		else if (parsetime.length() == 2)
		{
			hours += Integer.parseInt(parsetime.substring(0, 2));
		}
		else if (parsetime.length() == 1)
		{
			hours += Integer.parseInt(parsetime.substring(0, 1));
		}
		else
		{
			throw new NumberFormatException();
		}

		if (desc.endsWith("pm") && hours != 12)
		{
			hours += 12;
		}

		if (desc.endsWith("am") && hours == 12)
		{
			hours -= 12;
		}

		return hoursMinutesToTicks(hours, minutes);
	}

	public static long hoursMinutesToTicks(final int hours, final int minutes)
	{
		long ret = ticksAtMidnight;
		ret += (hours) * ticksPerHour;

		ret += (minutes / 60.0) * ticksPerHour;

		ret %= ticksPerDay;
		return ret;
	}

	public static long parseAlias(final String desc) throws NumberFormatException
	{
		final Integer ret = nameToTicks.get(desc);
		if (ret == null)
		{
			throw new NumberFormatException();
		}

		return ret;
	}

	public static boolean meansReset(final String desc)
	{
		return resetAliases.contains(desc);
	}

	// ============================================
	// FORMAT. From int to describing String
	// --------------------------------------------
	public static String format(final long ticks)
	{
		return _("timeFormat", format24(ticks), format12(ticks), formatTicks(ticks));
	}

	public static String formatTicks(final long ticks)
	{
		return (ticks % ticksPerDay) + "ticks";
	}

	public static String format24(final long ticks)
	{
		synchronized (SDFTwentyFour)
		{
			return formatDateFormat(ticks, SDFTwentyFour);
		}
	}

	public static String format12(final long ticks)
	{
		synchronized (SDFTwelve)
		{
			return formatDateFormat(ticks, SDFTwelve);
		}
	}

	public static String formatDateFormat(final long ticks, final SimpleDateFormat format)
	{
		final Date date = ticksToDate(ticks);
		return format.format(date);
	}

	public static Date ticksToDate(long ticks)
	{
		// Assume the server time starts at 0. It would start on a day.
		// But we will simulate that the server started with 0 at midnight.
		ticks = ticks - ticksAtMidnight + ticksPerDay;

		// How many ingame days have passed since the server start?
		final long days = ticks / ticksPerDay;
		ticks -= ticks * ticksPerDay;

		// How many hours on the last day?
		final long hours = ticks / ticksPerHour;
		ticks -= ticks * ticksPerHour;

		// How many minutes on the last day?
		final long minutes = (long)Math.floor(ticks / ticksPerMinute);
		final double dticks = ticks - minutes * ticksPerMinute;

		// How many seconds on the last day?
		final long seconds = (long)Math.floor(dticks / ticksPerSecond);

		// Now we create an english GMT calendar (We wan't no daylight savings)
		final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH);
		cal.setLenient(true);

		// And we set the time to 0! And append the time that passed!
		cal.set(0, Calendar.JANUARY, 1, 0, 0, 0);
		cal.add(Calendar.DAY_OF_YEAR, (int)days);
		cal.add(Calendar.HOUR_OF_DAY, (int)hours);
		cal.add(Calendar.MINUTE, (int)minutes);
		cal.add(Calendar.SECOND, (int)seconds + 1); // To solve rounding errors.

		return cal.getTime();
	}
}