为了账号安全,请及时绑定邮箱和手机立即绑定

将 Long 到 DateTime 从 C# 日期转换为 Java 日期

将 Long 到 DateTime 从 C# 日期转换为 Java 日期

C#
慕仙森 2021-10-09 14:07:15
我一直在尝试用Java读取二进制文件,二进制文件是用C#编写的。其中一些数据包含 DateTime 数据。当 DateTime 数据将写入文件(以二进制形式)时,它DateTime.ToBinary();在 C# 上使用。为了读取 DateTime 数据,它将首先使用 将字节转换为长数据,BitConverter.ToInt64(byte[], 0)然后使用 将其再次从 long 转换为 DateTime 数据DateTime.FromBinary(long)。(所有这些都是用 C# 编写的)。假设从字节转换后的长数据是 = -8586803256090942249,当将其转换为 DateTime 时,它将返回 = 3/17/2018 5:07:56 PM现在,我正在尝试使用 Java 读取该二进制文件。而对于字节的数据转换成长的数据,我用这个代码:ByteBuffer.wrap(byte[]).order(ByteOrder.LITTLE_ENDIAN).getLong()。它将像 C# 一样返回精确的长数据值。但是,当我尝试将其从长数据转换为 Java 中的 DateTime 时,使用Date date = new Date(long),它将返回 = Sun May 06 19:04:17 WIB 272097407。你能帮我解决这个问题的正确解决方案是什么吗?DateTime.FromBinary()Java 中的 C#是否有任何等价物?还是我的代码错了?非常感谢您的所有回答。
查看完整描述

1 回答

?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

在 Java 中:


    long fromBytes = -8586803256090942249L;


    // Mask out kind and ticks

    int kind = Math.toIntExact((fromBytes >> 62) & 0x3);

    long ticks = fromBytes & 0x3FFF_FFFF_FFFF_FFFFL;

    LocalDateTime cSharpEpoch = LocalDate.of(1, Month.JANUARY, 1).atStartOfDay();

    // 100 nanosecond units or 10^-7 seconds

    final int unitsPerSecond = 10_000_000;

    long seconds = ticks / unitsPerSecond;

    long nanos = (ticks % unitsPerSecond) * 100;

    LocalDateTime ldt = cSharpEpoch.plusSeconds(seconds).plusNanos(nanos);


    switch (kind) {

    case 0: // Unspecified

    case 2: // Local time

        System.out.println("Result LocalDateTime: " + ldt);

        break;


    case 1: // UTC

        OffsetDateTime utcDateTime = ldt.atOffset(ZoneOffset.UTC);

        System.out.println("Result OffsetDateTime in UTC: " + utcDateTime);

        break;


    default:

        System.out.println("Not a valid DateTimeKind: " + kind);

        break;

    }

输出:


结果 LocalDateTime: 2018-03-17T10:07:56.383355900


编辑:号码是


一个 64 位有符号整数,它对 2 位字段中的 Kind 属性和 62 位字段中的 Ticks 属性进行编码。


Tetsuya Yamamoto 是正确的,因为 ticks 属性表示自 0001/01/01 在一天开始(午夜)以来经过的 100 纳秒间隔数。类型为 0 表示未指定,1 表示 UTC 或 2 表示本地时间。所以我分别屏蔽了种类和刻度。


即使在您的情况下种类是 2,这应该是当地时间,但时间似乎确实是 UTC。这是打印的时间与您预期的印度尼西亚西部时间下午 5:07:56 一致的唯一方式。也许该数字是在时区设置为 UTC 的计算机上生成的。


要获取您所在时区的时间:


    ZoneId targetZone = ZoneId.of("Asia/Jakarta");

    ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC).withZoneSameInstant(targetZone);

    System.out.println("Converted to target time zone: " + zdt);

转换为目标时区:2018-03-17T17:07:56.383355900+07:00[亚洲/雅加达]


这与您所说的 C# 方面的内容一致。


PSDate如果可以,请避免使用Java 中的类,它早已过时且设计不佳,多年前被java.time 取代,现代 Java 日期和时间 API(我当然在上面使用过)。如果您确实需要一个Date无法更改或不想更改的遗留 API,正如您在评论中已经指出的,转换是这样的:


    Instant inst = ldt.atOffset(ZoneOffset.UTC).toInstant();

    Date date = Date.from(inst);

    System.out.println(date);

带有默认时区 Asia/Jakarta 的 JVM 上的输出:


2018 年 3 月 17 日星期六 17:07:56 WIB


致谢: Andreas 在回答(链接如下)中解释了 64 位数字的结构并提供了文档链接。我从那里拿走了它们。


查看完整回答
反对 回复 2021-10-09
  • 1 回答
  • 0 关注
  • 331 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信