Howdy there :> I wrote these methods to be able to easily parse a player's input of time into an easy-to-read string (eg 4w10h56m8s -> 4 weeks, 10 hours, 56 minutes and 8 seconds) as well as total milliseconds, for managing lengths of time, and thought I should share them for others to use/improve How to use Copy the source into a new class file called TimeParser.java In your classes, use TimeParser.<methodName>(arguments) Use the following methods: Methods TimeParser.parseString(String input) This will convert a time (eg 5h20m or 9w8d9h59s) into its total amount of milliseconds Code: String input = "4w17h10s"; long ms= parser.parseString(input); // ms takes the value of 2480410000 Any invalid characters (characters that are not w(eeks), d(ays), h(ours), m(inutes) or s(econds) eg. 28d7j9m43o7s)) or floating numbers (eg 10h6m89) are removed and not counted. If the input is not valid (eg 10k89), -1 will be returned. ----------------------- TimeParser.parseLong(long milliseconds, boolean abbreviate) This will convert any amount of milliseconds (outputted by .parseString()) to its worth in words. Example: 3345550000 milliseconds If abbreviate is set to true, the output will be: If it is set to false, the output will be: If the input is less than 1000 (1 second), it will return null. ----------------------- I hope you find this useful, and please leave any useful comments/critisism below TimeParser (Move your mouse to reveal the content) TimeParser (open) TimeParser (close) Code:java /*** @author Chinwe*/public class TimeParser{ /** * Parse a string input into milliseconds, using w(eeks), d(ays), h(ours), m(inutes) and s(econds) * For example: 4d8m2s -> 4 days, 8 minutes and 2 seconds * * @param string String to convert to milliseconds * @return Milliseconds */ public static long parseString (String string) { List<String> list = new ArrayList<String>(); String c; int goBack = 0; for (int i = 0; i < string.length(); i++) { c = String.valueOf(string.charAt(i)); if (c.matches("[a-zA-Z]")) { list.add(string.substring(goBack, i + 1)); goBack = i + 1; } } // Cleanse long amount; long total = 0; char ch; for (String st : list) { ch = st.charAt(st.length() - 1); if (st.length() != 1 && String.valueOf(ch).matches("[M,w,d,h,m,s]")) { // Total milliseconds amount = Math.abs(Integer.parseInt(st.substring(0, st.length() - 1))); switch (ch) { case 's': total += (amount * 1000); break; case 'm': total += (amount * 1000 * 60); break; case 'h': total += (amount * 1000 * 3600); break; case 'd': total += (amount * 1000 * 3600 * 24); break; case 'w': total += (amount * 1000 * 3600 * 24 * 7); break; } } } if (total == 0) return -1; return total; } /** * @param milliseconds Milliseconds to convert to words * @param abbreviate For example, if true, 293000 -> "10m-53s", otherwise "10 minutes and 53 seconds" * @return Time in words */ public static String parseLong (long milliseconds, boolean abbreviate) { // String[] units = new String[5]; List<String> units = new ArrayList<String>(); long amount; amount = milliseconds / (7 * 24 * 60 * 60 * 1000); units.add(amount + "w"); amount = milliseconds / (24 * 60 * 60 * 1000) % 7; units.add(amount + "d"); amount = milliseconds / (60 * 60 * 1000) % 24; units.add(amount + "h"); amount = milliseconds / (60 * 1000) % 60; units.add(amount + "m"); amount = milliseconds / 1000 % 60; units.add(amount + "s"); // Sort into order String[] array = new String[5]; char end; for (String s : units) { end = s.charAt(s.length() - 1); switch (end) { case 'w': array[0] = s; case 'd': array[1] = s; case 'h': array[2] = s; case 'm': array[3] = s; case 's': array[4] = s; } } units.clear(); for (String s : array) if (!s.startsWith("0")) units.add(s); // Append StringBuilder sb = new StringBuilder(); String word, count, and; char c; for (String s : units) { if (!abbreviate) { c = s.charAt(s.length() - 1); count = s.substring(0, s.length() - 1); switch (c) { case 'w': word = "week" + (count.equals("1") ? "" : "s"); break; case 'd': word = "day" + (count.equals("1") ? "" : "s"); break; case 'h': word = "hour" + (count.equals("1") ? "" : "s"); break; case 'm': word = "minute" + (count.equals("1") ? "" : "s"); break; default: word = "second" + (count.equals("1") ? "" : "s"); break; } and = s.equals(units.get(units.size() - 1)) ? "" : s.equals(units.get(units.size() - 2)) ? " and " : ", "; sb.append(count + " " + word + and); } else { sb.append(s); if (!s.equals(units.get(units.size() - 1))) sb.append("-"); } } return sb.toString().trim().length() == 0 ? null : sb.toString().trim(); } }
Good utility, I never could figure out how to do this . You might want to add that you need Java 7 for this because you can't switch strings in anything lower than 7.
Looks good, only thing I would change is instead of using a String for your switch case, just use a character like 'm' since you are only using one character anyways, and I believe character based switches have been implemented for a few java updates.
I like it. You could also have used Java's TimeUnit class. Example: total += TimeUnit.DAYS.toMillis(amount). However, that won't work for things like months.
Why are you forcing the instantiation? I haven't looked through the code so please forgive my ignorance, but for methods like this, can't you make them static?
TomFromCollege Yeah I think this should be able to be made static. Also, this is very long, there are much shorter ways of doing this.
Ah yes, good idea, changing now So I could have Reinventing the wheel ftw It most definitely can be made static, should I change it or just add a note that you can for convenience? I know But it orders the selection, removes any invalid characters etc, and works
Chinwe You really should change it, having to instantiate is an insane waste of memory if you can just use static I like it! Just make it static
Chinwe Looks nice! I tend to prefer an instantiable approach (less repeated processing). Here is what I use. This approach also (almost accidentally) allows you to use time unit abbreviations and spaces, meaning "5 mins 2 secs" is as valid as "5m2s". Also, input like "360s" will translate correctly to "6 minutes".
TomFromCollege Looks cleaner (in my opinion). In either case, if I want to do anything with the long result after I've processed it, I'll need to store it, so why not just store it in the class? I personally prefer methods with fewer parameters (i.e. new TimeLexer(input).toString() is cleaner than something like DateComparison.getDifference(TimeLexer.parseDate(input))). For the DateComparison class, I find instantiation to be nicer since once I store an instance of the class, I can directly work with the different time units, so if I want to just get how many days are in between two times, I can just use new DateComparison(time).getDays(). Also, to be honest, this is a simplified version of what I really use, which supports many more time contexts and covers a region of time instead of just one point (i.e. "6/14@noon" or "2d5h,1d"), so in that case the instantiation is necessary (since I need that to turn the output into a MySQL statement).
afistofirony I see what you're getting at, with more functionality I can see the need for instantiation (As you said: less repeated processing) It just seems a waste to create a new object when in reality you're only using it to store an integer, I realise I'm just nitpicking now but, only with more functionality could I see the need to instantiate