我在一个需要保存TDateTime
类型为 (Delphi) 的文件的 Android 项目中。我的日期以毫秒为单位,但我不知道如何将毫秒转换为TDateTime
.
我有这样的事情:
Date dateInMillis = new Date(System.currentTimeMillis());
double dateInDouble = ???;
我会很高兴任何可以帮助我解决这个问题的提示。
DelphiTDateTime
以天为单位测量时间。Java 遵循 Unix 标准并以毫秒为单位进行测量。要在两者之间进行转换,您需要按一天中的毫秒数进行缩放,86400000
.
另一个区别是两个系统使用不同的时代。Java 使用的 Unix 纪元是 1970 年 1 月 1 日 00:00。Delphi 纪元是 1899 年 12 月 30 日 00:00。以 Delphi 表示的 Unix 纪元TDateTime
是25569
.
因此,要将 Unix 纪元的毫秒转换为 Delphi 纪元的天数,请执行以下计算:
double delphiDateTime = unixMillis/86400000.0 + 25569.0;
最近发布了带有新日期时间类的 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
使用几年前取代类的现代java.timeDate
类。
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 中的现代java.time类,不要使用遗留类,例如java.util.Date
或java.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 使用一种从电子表格继承而来的糟糕的时间跟踪方法:使用double
浮点小数。
整数部分代表全天,一般的 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 ) ;
我们应该将结果截断到毫秒。要截断 a 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
结果 = 44033.997
警告:我没有测试过这段代码。而且我不使用Delphi。所以买家要小心:这个代码值得你付出的每一分钱。
LocalDateTime
注意:不要用来代表LocalDateTime
片刻。此类表示具有时间的日期,但缺少时区或与 UTC 的偏移量的上下文。例如,取 2021 年 1 月 23 日中午的值。那会是日本东京的中午吗?还是法国图卢兹的中午?还是在美国俄亥俄州托莱多的中午?那将是三个非常不同的时刻,相隔几个小时。如果缺少时区,我们不知道哪个是预期的。
由于LocalDateTime
Delphi(大概)使用 UTC,而 UTC 像LocalDateTime
. 但是LocalDateTime
从概念上讲,使用不适合这个问题,因为我们在这里需要一些时间。