public static @Nullable Duration fromCloudDuration(String duration) {
    Matcher matcher = DURATION_PATTERN.matcher(duration);
    if (!matcher.matches()) {
      return null;
    }
    long millis = Long.parseLong(matcher.group(1)) * 1000;
    String frac = matcher.group(2);
    if (frac != null) {
      long fracs = Long.parseLong(frac);
      if (frac.length() == 3) { // millisecond resolution
        millis += fracs;
      } else if (frac.length() == 6) { // microsecond resolution
        millis += fracs / 1000;
      } else if (frac.length() == 9) { // nanosecond resolution
        millis += fracs / 1000000;
      } else {
        return null;
      }
    }
    return Duration.millis(millis);
  }
@Test
  public void fromCloudDurationShouldParseDurationStrings() {
    assertEquals(Duration.millis(4000), fromCloudDuration("4s"));
    assertEquals(Duration.millis(4001), fromCloudDuration("4.001s"));
    assertEquals(Duration.millis(4001), fromCloudDuration("4.001000s"));
    assertEquals(Duration.millis(4001), fromCloudDuration("4.001001s"));
    assertEquals(Duration.millis(4001), fromCloudDuration("4.001000000s"));
    assertEquals(Duration.millis(4001), fromCloudDuration("4.001000001s"));
    assertNull(fromCloudDuration(""));
    assertNull(fromCloudDuration("4"));
    assertNull(fromCloudDuration("4.1"));
    assertNull(fromCloudDuration("4.1s"));
  }