Solved Time breakdown

Discussion in 'Plugin Development' started by Strahan, Sep 21, 2016.

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

    Strahan

    Hi. I know this isn't strictly an API question, but it does relate to my plugin. I want a user to be able to pass a duration argument for a ban command. I figured I'd store it as current time in millis + ban duration. I don't want the user to have to input seconds though, I figured a format of ##d##h##m##s for days/hours/mins/secs would be nice. This is what I'm doing now:

    Code:
      public Long banstop(Player p, String duration) {
          Long retval = 0l; String buffer = "";
          int[] multiplier = new int[116]; multiplier[100] = 86400; multiplier[104] = 3600; multiplier[109] = 60; multiplier[115] = 1;
          for (int x = 0; x < duration.length(); x++) {
              if ((int)duration.charAt(x) > 57) {
                  retval += Long.parseLong(buffer) * multiplier[(int)duration.charAt(x)];
                  buffer = "";
              } else {
                  buffer += duration.substring(x, x+1);
              }
          }
          return retval;
      }
    
    The reason for the multiplier int array is that I didn't want to have a big if/then or switch in the loop, I thought it'd be cleaner this way. True, I waste memory as I only use 4 positions in a 116 array but I didn't know a better way to handle that part.

    That function works, but I was curious if there is a better way to do it? Thanks!

    PS, I need to add some error handling because I just realized as it is now, it'll s**t itself if the user gives it malformed content lol.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
  2. Offline

    mine-care

    Well take a look at SimpleDateFormat and how to parse strings to dates. However you could build a small method to use a different system such as "/ban <user> 20m" where m =minutes.
    Specifically:
    S= seconds
    m=minutes
    H= hours
    D= days
    W= weeks
    M= months
    Y= years

    Minutes and months are case sensitive, but it will work ;)
     
    I Al Istannen likes this.
  3. Offline

    I Al Istannen

    @Strahan @mine-care
    My time to shine :p Don't know if my version is "better" though :p
    It is a recursive parser, that accepts milliseconds, ticks, seconds, minutes hours and days. It will throw a RuntimeException if an error occurs and doesn't care about order or whatever in the message. As long as it follows the format it can be anything from "1s" to "1w 1s 99h 20w 5s 7S 6t" and so on.

    The grammar is the following:
    part -> number+
    number -> NUMBER UNIT
    NUMBER: 0-9+
    UNIT: S | t | s | m | h | d

    The ones in capital are only help constructs and no productions.

    You can add new units by just extending UNIT. Just add some more else if statements at the bottom.

    Code:java
    1.  
    2. /**
    3.   * Small recursive parser by I Al Istannen. Bug me about it, I know it is bad!
    4.   * <p>
    5.   * Format:
    6.   * <br>"xxS" ==> milliseconds
    7.   * <br>"xxt" ==> ticks
    8.   * <br>"xxs" ==> seconds
    9.   * <br>"xxm" ==> minutes
    10.   * <br>"xxh" ==> hours
    11.   * <br>"xxd" ==> days
    12.   *
    13.   * @param input The input string
    14.   *
    15.   * @return The time in milliseconds
    16.   *
    17.   * @throws RuntimeException If an error occurred while parsing.
    18.   */
    19. public static long parseDurationToTicks(String input) throws RuntimeException {
    20. return parseDuration(input) / 50;
    21. }
    22.  
    23. /**
    24.   * Small recursive parser by I Al Istannen. Bug me about it, I know it is bad!
    25.   * <p>
    26.   * Format:
    27.   * <br>"xxS" ==> milliseconds
    28.   * <br>"xxt" ==> ticks
    29.   * <br>"xxs" ==> seconds
    30.   * <br>"xxm" ==> minutes
    31.   * <br>"xxh" ==> hours
    32.   * <br>"xxd" ==> days
    33.   *
    34.   * @param input The input string
    35.   *
    36.   * @return The time in milliseconds
    37.   *
    38.   * @throws RuntimeException If an error occurred while parsing.
    39.   */
    40. public static long parseDuration(String input) throws RuntimeException {
    41. return new Object() {
    42.  
    43. private int pos = -1, ch;
    44.  
    45. /**
    46.   * Goes to the next char
    47.   */
    48. private void nextChar() {
    49. ch = ++pos < input.length() ? input.charAt(pos) : -1;
    50. }
    51.  
    52. /**
    53.   * Eats a char
    54.   *
    55.   * @param charToEat The chat to eat
    56.   * @return True if the char was found and eaten
    57.   */
    58. private boolean eat(int charToEat) {
    59. while (ch == ' ') {
    60. nextChar();
    61. }
    62. if (ch == charToEat) {
    63. nextChar();
    64. return true;
    65. }
    66. return false;
    67. }
    68.  
    69. public long parse() {
    70. nextChar();
    71. return parsePart();
    72. }
    73.  
    74. private long parsePart() {
    75. long number = parseNumber();
    76. while (ch != -1) {
    77. number += parseNumber();
    78. }
    79.  
    80. return number;
    81. }
    82.  
    83. private long parseNumber() {
    84. while (ch == ' ') {
    85. nextChar();
    86. }
    87. long number;
    88. int start = pos;
    89. if (ch >= '0' && ch <= '9') {
    90. while (ch >= '0' && ch <= '9') {
    91. nextChar();
    92. }
    93. number = Long.parseLong(input.substring(start, pos));
    94.  
    95. if (eat('S')) {
    96. // well, it is already in ms
    97. }
    98. else if (eat('s')) {
    99. number *= 1000;
    100. }
    101. else if (eat('m')) {
    102. number = TimeUnit.MINUTES.toMillis(number);
    103. }
    104. else if (eat('h')) {
    105. number = TimeUnit.HOURS.toMillis(number);
    106. }
    107. else if (eat('d')) {
    108. number = TimeUnit.DAYS.toMillis(number);
    109. }
    110. else if (eat('t')) {
    111. number *= 50;
    112. }
    113. else {
    114. throw new RuntimeException("No unit given near pos " + pos + " starting at " + start);
    115. }
    116. }
    117. else {
    118. throw new RuntimeException("Unexpected char at pos " + pos + " " + ch + " '" + (char) ch + "'");
    119. }
    120.  
    121. return number;
    122. }
    123.  
    124. }.parse();
    125. }
     
    mine-care likes this.
  4. Offline

    Strahan

    Thanks!
     
  5. Offline

    I Al Istannen

    @Strahan
    No problem. It is certainly not the most efficient way, but I think it works ;)
     
Thread Status:
Not open for further replies.

Share This Page