Java 时间 API 根据年表从 sql 时间戳中获取偏移量

Java Time API get offset from sql Timestamp given the Chronology

我有以下代码,它使用 Joda 时间库从 sql 时间戳对象获取偏移量。

public static long getOffset(Chronology chronology_, Timestamp timeStamp_)
  {
    long offset = 0;
    if (chronology_ != null)
      {
        offset = chronology_.getZone().getOffset(new DateTime(timeStamp_).getMillis());
      }
    return offset;
  }

如何使用 Java 8 API 实现相同的效果。我不确定是否还需要年表。

虽然 Joda-Time 的年表概念和 java.time (JSR-310) 的年表概念相似,但在您的情况下有一个重要的区别:Joda-Time Chronology 可能(可选)有一个时区。 java.time.chrono.Chronology 不能。因此,您需要以其他方式提供用于操作的时区,而不是通过年表。

现在开始了,我可能建议您还可以通过 java.sql.Timestamp 以外的其他方式提供时间点。所以一种选择是:

public static long getOffset(ZoneId zone, Instant when)
{
    long offset = 0;
    if (zone != null)
    {
        int offsetSeconds = zone.getRules()
                .getOffset(when)
                .getTotalSeconds();
        offset = TimeUnit.SECONDS.toMillis(offsetSeconds);
    }
    return offset;
}

如果您的来电者从遗留 API 中得到了他们无法更改的老式 Timestamp,则他们应该转换。所以调用上述方法的一种方法是:

    long offsetMillis = getOffset(
            ZoneId.of("Africa/Khartoum"), theirTimesatmp.toInstant());
    System.out.println(offsetMillis);

使用现在时间戳的示例输出:

7200000

Timestamp class 设计不佳,是在已经设计不佳的 java.util.Date class 之上的真正 hack,因此我们不应该使用它。如果我们无法避免得到一个,我们应该立即将其转换为 InstantLocalDateTime 并从那里执行或进一步工作。

如果您的方法 returns 从 getOffset() 返回 ZoneOffset 对象而不是一个可能让调用者怀疑它是秒、毫秒还是一些其他单位。

如果你确实坚持提供一个方便的方法来接受一个Timestamp,你当然可以添加一个对过去友好的包装器。例如:

/** @deprecated use {@link #getOffset(ZoneId, Instant)} instead */
public static long getOffset(ZoneId zone, Timestamp timeStampParam)
{
    return getOffset(zone, timeStampParam.toInstant());
}

Link: Converting from Joda-Time to java.time 在 Stephen Colebourne 的博客上