当前位置: 首页 > 知识库问答 >
问题:

手动转换java时的奇怪行为。sql。LocalDate的时间戳

谭晓博
2023-03-14

我构建了一个小函数来将TimeStamp转换成LocalDate,并偶然发现了奇怪的行为。下面是代码:

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Test {

  private static void convert(long seconds) {
    System.out.printf("At %d seconds%n", seconds);
    Timestamp t = new Timestamp(seconds * 1000L);
    System.out.format("Timestamp: %s%n", t);
    Instant i = t.toInstant();
    System.out.format("Instant:   %s%n", i);
    ZonedDateTime atZone = i.atZone(ZoneId.systemDefault());
    System.out.format("at Zone:   %s%n", atZone);
    LocalDate localDate = atZone.toLocalDate();
    System.out.format("LocalDate: %s%n", localDate);
  }
}

我当地的时区是欧洲/柏林。现在,当调用时间戳0时,我得到正确的结果:

At 0 seconds
Timestamp: 1970-01-01 01:00:00.0
Instant:   1970-01-01T00:00:00Z
at Zone:   1970-01-01T01:00+01:00[Europe/Berlin]
LocalDate: 1970-01-01

一切如期而至。但当我把它命名为第一年的日期时,它辜负了我的期望:

At -62135769600 seconds
Timestamp: 0001-01-01 01:00:00.0
Instant:   0000-12-30T00:00:00Z
at Zone:   0000-12-30T00:53:28+00:53:28[Europe/Berlin]
LocalDate: 0000-12-30

问题:

  1. 转换为Instant后缺少一天,所以UTC和欧洲/柏林的时区似乎在当时相隔一天加一小时

共有2个答案

赫连昕
2023-03-14

问题似乎是由您的输入参数转换函数引起的。“-62135769600秒”显示您的输入值超过了烧焦的长限制。下面是输入值的测试输出,表示第一年(370 * 24 * 60 * 60)的时间戳。

At 31968000 seconds
Timestamp: 1971-01-06 01:00:00.0
Instant:   1971-01-06T00:00:00Z
at Zone:   1971-01-06T01:00+01:00[Europe/Berlin]
LocalDate: 1971-01-06
卫甫
2023-03-14

下面是Javadoc的片段,它暗示了早年的事情有点搞笑

格里高利历实现proleptic格里高利历和朱利安历法。也就是说,日期是通过无限期地向后和向前推断当前规则来计算的。因此,格雷戈里安日历可以用于所有年份,以产生有意义和一致的结果。然而,使用格里高利历获得的日期只有从公元3月1日起才是历史上准确的,当时现代儒略历规则被采用。在此日期之前,闰年规则被不定期地应用,在公元前45年之前,儒略历甚至不存在。

https://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html

如果你打开GregorianCalendar的来源,你会发现另一个可爱的“实施说明”,它暗示了更多的疯狂:

 * Likewise, with the Julian calendar, we assume a consistent
 * 4-year leap year rule, even though the historical pattern of
 * leap years is irregular, being every 3 years from 45 BCE
 * through 9 BCE, then every 4 years from 8 CE onwards, with no
 * leap years in-between.  Thus date computations and functions
 * such as isLeapYear() are not intended to be historically
 * accurate.

我已经编写了一个日期转换库,我相信它以一种“预期”的方式实现了日期类型之间的转换:https://github.com/beirtipol/date-converters.我希望能够在java之间提供一致的转换。util和java。时间是1582年以前(朱利安)-

为了回答你的部分问题,我不确定是否有一种可靠的方法可以在1582年之前不测试每个日期和时区就做到这一点。我正在尝试这样做,如果我弄明白了,我会发回,但前面还有很长的路要走!

这里有更多关于罗马-朱利安-格里高利转变乐趣的信息:https://www.timeanddate.com/calendar/julian-calendar.html

 类似资料:
  • 问题内容: 令人难以置信。为什么输出-124? 问题答案: 在Java中,an 是32位。A 是8 。 最原始的类型Java中的签名,,,,和long被编码在二进制补码。(类型为unsigned,并且sign的概念不适用于。) 在此数字方案中,最高有效位指定数字的符号。如果需要更多位,则将最高有效位(“ MSB”)简单复制到新的MSB中。 因此,如果你具有 并将其表示为 32位,则只需将1复制到左

  • 我遇到了奇怪的问题时,铸造小数到双倍。 以下代码返回true: 但是,当我将其强制转换为双倍时,它返回false: 这是记录在案的行为吗?当我被迫将decimal转换为Double时,我如何避免它? Visual Studio的截图: 将Math.round铸造为双倍me,结果如下: null 不幸的是,我不能在较小的项目中重现这个问题。我想埃里克的回答解释了原因。

  • 我有以下代码: 假设我现在将电脑的时区设置为太平洋时间(PDT为UTC-7),则打印 2012年6月29日星期五08:15:00太平洋标准时间 PDT不是比IST(印度标准时间)晚12.5小时吗?这个问题在任何其他时区都不会发生-我尝试了UTC、PKT、MMT等,而不是日期字符串中的IST。Java中有两个IST吗? 注意:实际代码中的日期字符串来自外部源,因此我不能使用GMT偏移量或任何其他时区

  • 问题内容: 这个问题已经在这里有了答案 : 为什么对泛型的这种使用不会引发运行时或编译时异常? (3个答案) 2年前关闭。 我正在使用Java 8。 我最近遇到了这个问题: 这不会引发java.lang.ClassCastException。这是为什么? 我一直在想和打电话。但是,当我尝试这样做时,它会按预期抛出异常。 问题答案: 它不会抛出,因为所有通用类型信息都已从编译后的代码中剥离(此过程称

  • 为了方便起见,我想创建datetime的子类。时间三角洲。这样做的目的是定义一个类: 所以我可以快速创建这样的时间增量: 然而,上面的代码产生了n天而不是n小时的时间增量。例如,请看以下ipython会话: 我无法解释这一点。有人吗?

  • 我正在使用Mapstruct映射将一个POJO转换为另一个POJO模型 以下是mapstruct自动生成的方法 该方法基本上获取源POJO的映射,并将其转换为目标模型的映射。生成正在通过。 当我运行代码时,我在这个方法中得到了ClassCast异常:HeaderAttributeGenericDataTypeMaptoStringEnergiectAttributeDataMap 堆栈跟踪: 我还