在Java中将毫秒转换为TDateTime

4

我正在一个需要使用TDateTime类型(Delphi)保存文件的Android项目中。我有毫秒级的日期,但我不知道如何将毫秒转换为TDateTime

我有类似这样的代码:

Date dateInMillis = new Date(System.currentTimeMillis());
double dateInDouble = ???;

我很乐意接受任何有助于解决这个问题的提示。


使用Java的DateTime函数将毫秒转换为DateTime。 - Metalhead1247
3个回答

10

Delphi的TDateTime以天为单位来测量时间。Java遵循Unix标准,以毫秒为单位度量时间。要在两者之间进行转换,需要按照一天内的毫秒数86400000 进行缩放。

另一个区别是两个系统使用不同的时间起点。Java使用的Unix纪元是1970年1月1日00:00。Delphi纪元是1899年12月30日00:00。用Delphi的TDateTime表示的Unix纪元为25569

因此,要将从Unix纪元以毫秒为单位计算的时间转换为从Delphi纪元以天为单位计算的时间,需要执行以下计算:

double delphiDateTime = unixMillis/86400000.0 + 25569.0;

那就是我几分钟前所做的!我需要等待8小时才能回答自己的问题,但这正是我所做的!谢谢David。 - Daniel S.

1

最近,随着Java 8的发布和新的日期时间类,以下代码应该可以正常工作:

LocalDateTime localDateTime = LocalDateTime.of(1899, 12, 30, 0, 0);//Delphi date EPOCH time start
double fraction = val % 1;
long intPart = (long) (val - fraction);
localDateTime = localDateTime.plus(intPart, ChronoUnit.DAYS);
localDateTime = localDateTime.plus((long) (24*60*60*1000 * fraction), ChronoUnit.MILLIS); //fraction is a fraction of the time of day

1

简述

使用现代的java.time类,这些类在多年前取代了Date类。

Duration duration =
        Duration.between(
                LocalDate.of( 1899 , Month.DECEMBER , 30 ).atStartOfDay( ZoneOffset.UTC ).toInstant() ,  // Epoch reference moment used by Delphi.
                Instant.now()  // Current moment as seen in UTC.
        );
double temp =
        // Get a whole number of days (integer ) + a decimal fraction of partial day = a `double` number = the `TDateTime` type in Delphi.
        duration.toDays() +
                (
                        ( double ) duration.minusDays( duration.toDays() ).toMillis()     // Milliseconds in our partial day.
                                /
                                ( double ) Duration.ofDays( 1 ).toMillis()                // Milliseconds in a full day, a generic 24-hour day.
                );
double r = Math.floor( temp * 1000 ) / 1000;  // Truncate to third decimal place to represent a resolution of milliseconds, the limit of `TDateTime` type in Delphi.

java.time

在Java中只使用现代的java.time类,永远不要使用旧的类,如java.util.Datejava.sql.Date

以UTC为准捕获当前时刻。

Instant now = Instant.now() ;  

由于某些扭曲的历史原因,Delphi 的 TDateTime 类使用 1899-12-30 的第一个时刻作为其纪元参考,可能是在UTC中。对于日期部分,请使用LocalDate。有关详细信息,请参见扭曲的历史
LocalDate delphiEpochDate = LocalDate.of( 1899 , Month.DECEMBER , 30 ); // No, not the 31st, the 30th.

epochDate.toString(): 1899-12-30

作为一种习惯,让java.time确定一天的第一个时刻,因为并不是所有日期在所有时区的时间都是00:00。

Instant delphiEpochMoment = delphiEpochDate.atStartOfDay( ZoneOffset.UTC ).toInstant();

odt.toString(): 1899-12-30T00:00Z

Delphi使用从电子表格继承的可怕时间跟踪方法:使用双精度浮点小数。

整数部分表示完整的天数,通用的24小时长的天数,忽略政治时间的异常。对于这样的经过时间,我们使用Duration

Duration d = Duration.between( delphiEpochMoment , now ) ;
long days = d.toDays() ;  // Generic 24-hour long days.

接下来,获取表示24小时一部分的小数部分。首先,我们减去完整天数的数量,以便剩下部分天数。

Duration partialDay = d.minusDays( days ) ;

然后将部分金额除以一整天的长度。我们将使用毫秒的分辨率而不是Duration的纳秒能力,因为似乎Delphi仅限于毫秒。
double millisOfPartialDay = partialDay.toMillis() ;
double millisOfFullDay = Duration.ofDays( 1 ).toMillis() ;
double tempResult = ( millisOfPartialDay / millisOfFullDay ) ;

我们应该将结果截断到毫秒。如果要截断一个 double,请参见此答案。而且我们应该添加整数天数。
double tempResult = days + ( millisOfPartialDay / millisOfFullDay ) ;
double result = Math.floor( tempResult * 1000 ) / 1000 ;

把这一切放在一起。
Instant now = Instant.now();

LocalDate delphiEpochDate = LocalDate.of( 1899 , Month.DECEMBER , 30 ); // No, not the 31st, the 30th.
Instant delphiEpochMoment = delphiEpochDate.atStartOfDay( ZoneOffset.UTC ).toInstant();

Duration d = Duration.between( delphiEpochMoment , now );
long days = d.toDays();  // Generic 24-hour long days.

Duration partialDay = d.minusDays( days );

double millisOfPartialDay = partialDay.toMillis();
double millisOfFullDay = Duration.ofDays( 1 ).toMillis();

double tempResult = days + ( millisOfPartialDay / millisOfFullDay );
double result = Math.floor( tempResult * 1000 ) / 1000;  // Truncate to third decimal place to represent a resolution of milliseconds.

System.out.println( "delphiEpochMoment = " + delphiEpochMoment );
System.out.println( "d = " + d );
System.out.println( "tempResult = " + tempResult );
System.out.println( "result = " + result );

delphiEpochMoment = 1899-12-30T00:00:00Z

d = PT1056815H56M10.613011S

tempResult = 44033.99734505787

result = 44033.997

Caveat: 我没有测试这段代码,也不使用Delphi。所以买家要小心:这段代码值得你花费的每一分钱。

避免使用LocalDateTime

注意:不要使用LocalDateTime来表示一个时刻。这个类表示带有时间的日期,但缺少时区或UTC偏移量的上下文。例如,取2021年1月23日中午12点的值。那是日本东京的中午?还是法国图卢兹的中午?或者是美国俄亥俄州托莱多的中午?这些将是几个小时之间非常不同的时刻。如果缺少时区,我们不知道哪个是预期的。

您可以在 Delphi 时间跟踪的这个特定问题中使用 LocalDateTime,因为 Delphi(假设)使用 UTC,而 UTC 使用通用的 24 小时长的天,与 LocalDateTime 相同。但是,在这个问题中使用 LocalDateTime 在概念上不适合,因为我们需要这里的时刻。

Table of date-time types in Java, both modern and legacy


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接