[Util] TimeParser

Discussion in 'Resources' started by Chinwe, Aug 30, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    Chinwe

    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 (open)

    Code:java
    1. /**
    2. * @author Chinwe
    3. */
    4. public class TimeParser
    5. {
    6.  
    7. /**
    8.   * Parse a string input into milliseconds, using w(eeks), d(ays), h(ours), m(inutes) and s(econds)
    9.   * For example: 4d8m2s -> 4 days, 8 minutes and 2 seconds
    10.   *
    11.   * @param string String to convert to milliseconds
    12.   * @return Milliseconds
    13.   */
    14. public static long parseString (String string)
    15. {
    16. List<String> list = new ArrayList<String>();
    17.  
    18. String c;
    19. int goBack = 0;
    20. for (int i = 0; i < string.length(); i++)
    21. {
    22. c = String.valueOf(string.charAt(i));
    23. if (c.matches("[a-zA-Z]"))
    24. {
    25. list.add(string.substring(goBack, i + 1));
    26. goBack = i + 1;
    27.  
    28. }
    29. }
    30. // Cleanse
    31. long amount;
    32. long total = 0;
    33. char ch;
    34. for (String st : list)
    35. {
    36. ch = st.charAt(st.length() - 1);
    37. if (st.length() != 1 && String.valueOf(ch).matches("[M,w,d,h,m,s]"))
    38. {
    39. // Total milliseconds
    40. amount = Math.abs(Integer.parseInt(st.substring(0, st.length() - 1)));
    41. switch (ch)
    42. {
    43. case 's':
    44. total += (amount * 1000);
    45. break;
    46. case 'm':
    47. total += (amount * 1000 * 60);
    48. break;
    49. case 'h':
    50. total += (amount * 1000 * 3600);
    51. break;
    52. case 'd':
    53. total += (amount * 1000 * 3600 * 24);
    54. break;
    55. case 'w':
    56. total += (amount * 1000 * 3600 * 24 * 7);
    57. break;
    58. }
    59.  
    60. }
    61. }
    62.  
    63. if (total == 0) return -1;
    64.  
    65. return total;
    66. }
    67.  
    68. /**
    69.   * @param milliseconds Milliseconds to convert to words
    70.   * @param abbreviate For example, if true, 293000 -> "10m-53s", otherwise "10 minutes and 53 seconds"
    71.   * @return Time in words
    72.   */
    73. public static String parseLong (long milliseconds, boolean abbreviate)
    74. {
    75. // String[] units = new String[5];
    76. List<String> units = new ArrayList<String>();
    77. long amount;
    78.  
    79. amount = milliseconds / (7 * 24 * 60 * 60 * 1000);
    80. units.add(amount + "w");
    81.  
    82. amount = milliseconds / (24 * 60 * 60 * 1000) % 7;
    83. units.add(amount + "d");
    84.  
    85. amount = milliseconds / (60 * 60 * 1000) % 24;
    86. units.add(amount + "h");
    87.  
    88. amount = milliseconds / (60 * 1000) % 60;
    89. units.add(amount + "m");
    90.  
    91. amount = milliseconds / 1000 % 60;
    92. units.add(amount + "s");
    93.  
    94.  
    95. // Sort into order
    96. String[] array = new String[5];
    97. char end;
    98. for (String s : units)
    99. {
    100. end = s.charAt(s.length() - 1);
    101. switch (end)
    102. {
    103. case 'w':
    104. array[0] = s;
    105. case 'd':
    106. array[1] = s;
    107. case 'h':
    108. array[2] = s;
    109. case 'm':
    110. array[3] = s;
    111. case 's':
    112. array[4] = s;
    113. }
    114. }
    115.  
    116. units.clear();
    117. for (String s : array)
    118. if (!s.startsWith("0")) units.add(s);
    119.  
    120.  
    121. // Append
    122. StringBuilder sb = new StringBuilder();
    123. String word, count, and;
    124. char c;
    125. for (String s : units)
    126. {
    127. if (!abbreviate)
    128. {
    129. c = s.charAt(s.length() - 1);
    130. count = s.substring(0, s.length() - 1);
    131. switch (c)
    132. {
    133. case 'w':
    134. word = "week" + (count.equals("1") ? "" : "s");
    135. break;
    136. case 'd':
    137. word = "day" + (count.equals("1") ? "" : "s");
    138. break;
    139. case 'h':
    140. word = "hour" + (count.equals("1") ? "" : "s");
    141. break;
    142. case 'm':
    143. word = "minute" + (count.equals("1") ? "" : "s");
    144. break;
    145. default:
    146. word = "second" + (count.equals("1") ? "" : "s");
    147. break;
    148. }
    149.  
    150. and = s.equals(units.get(units.size() - 1)) ? "" : s.equals(units.get(units.size() - 2)) ? " and " : ", ";
    151. sb.append(count + " " + word + and);
    152. } else
    153. {
    154. sb.append(s);
    155. if (!s.equals(units.get(units.size() - 1)))
    156. sb.append("-");
    157. }
    158.  
    159.  
    160. }
    161. return sb.toString().trim().length() == 0 ? null : sb.toString().trim();
    162.  
    163. }
    164.  
    165.  
    166. }

     
  2. Offline

    RainoBoy97

  3. Offline

    Loogeh

    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.
     
  4. Offline

    MrTwiggy

    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.
     
  5. Offline

    chasechocolate

    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.
     
  6. Offline

    TomFromCollege

    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?
     
  7. Offline

    Loogeh

    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.
     
  8. Offline

    Chinwe

    Ah yes, good idea, changing now :)


    So I could have :eek: 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? :rolleyes:

    I know :( But it orders the selection, removes any invalid characters etc, and works :)
     
  9. Offline

    TomFromCollege

    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 likes this.
  10. Offline

    Chinwe

  11. Offline

    afistofirony

    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".
     
  12. Offline

    TomFromCollege

    afistofirony
    In what way would instantiating help you with these methods?
     
  13. Offline

    afistofirony

    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).
     
  14. Offline

    TomFromCollege

    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 :)
     
    afistofirony likes this.
  15. Offline

    waremanu

    This looks not only awesome, it is! Thank you! :)
     
Thread Status:
Not open for further replies.

Share This Page