Java 将十六进制 UTF8 转换为 UTF-16

Java convert hex UTF8 to UTF-16

我正在通过数据捕获产品从大型机发送一些交易数据(json 格式)。在 JSON 中,它们应该发送一个值,该值是大型机 timeOfDay (TOD) 值,表示等效的事务时间戳。 而不是发送值 "stck":"00d2fde04305b72642"

他们反而寄给我 "stck":"\u00c3\u0092\u00c3\u00bd\u00c2\u00aa\u00c2\u009e\u001c\u00c2\u0089\u001cG"

当我问他们为什么他们说

"以上 ("stck":"00d2fde04305b72642") 是二进制数据 UTF-16 格式。JSON 不适用于二进制数据,因此我们已将其转换为十六进制 UTF-8格式。而且你可以在你这边将它转换回 UTF-16"

我在 java 需要帮助。我看到了多个问题,但没有什么能完全按照我想做的将十六进制 UTF-8 转换为 UTF-16,这应该看起来像“00d2fde04305b72642”

我找到了一个问题,该问题显示了如何使用 java 将生成的 TOD 值 ("stck":"00d2fde04305b72642") 转换为事务时间戳,因此我在该部分进行了介绍。

"They" 做错了。他们应该简单地以 base-16 编码数值并使用结果字符串。

他们所做的是将数值的字节视为字符,并使用 UTF-8 对其进行编码。然后他们获取这些字节并对非 ASCII 字符应用 Unicode 转义序列。雪上加霜的是,当被问及这个过程时,他们的回答是胡说八道。这在很多层面上都是一场灾难。

以下应该允许您恢复数据并转换为 Java 时间戳。

import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;

public class SO45704851
{

  public static void main(String... argv)
    throws Exception
  {
    String example = "\u00c3\u0092\u00c3\u00bd\u00c2\u00aa\u00c2\u009e\u001c\u00c2\u0089\u001cG";
    long tod = sbrogliare(example);
    System.out.printf("ToD: 0x%016x%n", tod);
    Instant time = toInstant(tod);
    System.out.printf("Instant: %s%n", time);
  }

  /**
   * Clean up an infernal mess, miraculously bestowing a 64-bit time-of-day.
   */
  public static long sbrogliare(String garbage)
  {
    byte[] utf8 = new byte[garbage.length()];
    for (int idx = 0; idx < garbage.length(); ++idx)
      utf8[idx] = (byte) garbage.charAt(idx);
    String raw = new String(utf8, StandardCharsets.UTF_8);
    if (raw.length() != 8)
      throw new IllegalArgumentException();
    long n = 0;
    for (int idx = 0; idx < raw.length(); ++idx) {
      char ch = raw.charAt(idx);
      if (ch > 255)
        throw new IllegalArgumentException();
      n = n << 8 | ch;
    }
    return n;
  }

  private static final OffsetDateTime zero = OffsetDateTime.parse("1900-01-01T00:00Z");

  /**
   * Convert 64-bit time-of-day to {@code Instant}.
   */
  public static Instant toInstant(long tod)
  {
    long nanos = (125 * (tod >>> 32) << 23) + (125 * (tod & 0xFFFFFFFFL) >>> 9);
    return zero.plus(nanos, ChronoUnit.NANOS).toInstant();
  }

}