public static GenericRecord data(PartitionSpec spec, String partitionPath) {
    GenericRecord data = genericRecord(spec);
    String[] partitions = partitionPath.split("/", -1);
    Preconditions.checkArgument(
        partitions.length <= spec.fields().size(),
        "Invalid partition data, too many fields (expecting %s): %s",
        spec.fields().size(),
        partitionPath);
    Preconditions.checkArgument(
        partitions.length >= spec.fields().size(),
        "Invalid partition data, not enough fields (expecting %s): %s",
        spec.fields().size(),
        partitionPath);

    for (int i = 0; i < partitions.length; i += 1) {
      PartitionField field = spec.fields().get(i);
      String[] parts = partitions[i].split("=", 2);
      Preconditions.checkArgument(
          parts.length == 2 && parts[0] != null && field.name().equals(parts[0]),
          "Invalid partition: %s",
          partitions[i]);

      String value;
      if ("null".equals(parts[1])) {
        value = null;
      } else {
        try {
          /*
          Decode URL with UTF-8, because in org.apache.iceberg.PartitionSpec#escape,
          the value is encoded to URL with UTF-8
           */
          value = URLDecoder.decode(parts[1], "UTF-8");
        } catch (UnsupportedEncodingException e) {
          throw new IllegalStateException(
              String.format("failed to decode %s of %s", parts[1], partitionPath), e);
        }
      }

      data.set(
          i,
          MixedDataFiles.fromPartitionString(
              field, spec.partitionType().fieldType(parts[0]), value));
    }

    return data;
  }
return the number of hours away from the epoch, reverse {@link TransformUtil#humanHour}
amoro-format-iceberg/src/main/java/org/apache/amoro/utils/MixedDataFiles.java