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

时间戳。getTime()将时间戳值视为系统时区中的时间

董谦
2023-03-14

假设我有一个时间戳值。

编辑

Calendar curCal = new GregorianCalendar(TimeZone.getDefault());
    curCal.setTimeInMillis(System.currentTimeMillis());

    TimeZone fromTz = TimeZone.getDefault();            
    curCal.setTimeZone(fromTz);            

    TimeZone gmtTZ = TimeZone.getTimeZone("GMT");            
    Calendar toCal = new GregorianCalendar(gmtTZ);
    toCal.setTimeInMillis(curCal.getTimeInMillis());

    Date dd = toCal.getTime();
    SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a",Locale.US);
    format.setTimeZone(gmtTZ);
    String ff = format.format(dd);

    java.sql.Timestamp curTimeInGMT = new java.sql.Timestamp(dateInLong(ff, "dd/MM/yyyy hh:mm:ss a"));

现在我正在使用getTime()获取上述时间的毫秒值;

Long l = t.getTime();

根据Java文档,getTime()方法的定义是返回自1970年1月1日00:00:00 GMT以来的毫秒数,由这个Timestamp对象表示

因此,根据我多次测试的理解,getTime()将给出给定时间与1970年1月1日00:00:00 GMT之间的毫秒差。

对于getTime()要获得1月1, 1970, 00:00:00GMT的差异,它需要另一个GMT时间。因此它需要将给定时间转换为GMT时间。对于该转换,它需要给定时间的时区。它将考虑给定时间的时区作为SYSTEM TIME ZONE,它将获得相应的GMT时间,然后它将找到两个GMT时间之间的差异,它将返回差异。

我的理解正确吗?


共有2个答案

常英纵
2023-03-14

有两点可以让这项工作更容易:

  • 使用日期时间对象而不是字符串
    您应该使用JDBC来提取java。sql。来自数据库的时间戳对象,而不是这些日期时间值的字符串表示形式

首先,我们必须指定一个格式化程序来解析输入字符串,或者修改它以满足java中默认使用的ISO 8601标准。时间ISO 8601格式接近SQL格式,将中间的空格替换为T。

String input = "2016-01-08 08:03:52.0";
String inputIso8601 = input.replace ( " ", "T" );

将该字符串解析为本地日期时间,这意味着任何地点。输入字符串缺少任何时区或UTC偏移信息,因此我们从本地开始,然后应用假设的时区。

LocalDateTime localDateTime = LocalDateTime.parse ( inputIso8601 );

让我们应用假设的时区。我任意选择蒙特利尔,但显然您需要知道并使用该字符串输入的任何时区。如果您确定字符串表示UTC,请使用ZoneOffset。UTC

ZoneId zoneId = ZoneId.of ( "America/Montreal" ); // Or perhaps ZoneOffset.UTC constant.
ZonedDateTime zdt = ZonedDateTime.of ( localDateTime, zoneId );

现在我们准备转换成java。sql。要发送到数据库的时间戳对象。这个旧类有一个新方法,用于与java进行转换。时间物体。转换需要一个即时对象,它是UTC时间轴上的一个时刻。我们可以从我们的ZoneDateTime中提取一个即时

Instant instant = zdt.toInstant ( );
java.sql.Timestamp ts = java.sql.Timestamp.from ( instant );

转储到控制台。

System.out.println ( "input: " + input + " in ISO 8601: " + inputIso8601 + " is localDateTime: " + localDateTime + " in zoneId: " + zoneId + " is zdt: " + zdt + " gives instant: " + instant + " which converts to java.sql.Timestamp ts: " + ts );

输入:2016-01-08 08:03:52.0在ISO8601: 2016-01-08T08:03:52.0是localDateTime: 2016-01-08T08:03:52在zoneId: America/蒙特利尔是zdt: 2016-01-08T08:03:52-05:00[America/蒙特利尔]给出即时: 2016-01-08T13:03:52Z其中转换为java.sql.时间戳ts:2016-01-08 05:03:52.0

仔细阅读该控制台输出。注意ts上的一天中的时间。这显示了java.sql.Timestamp方法toString在生成日期-时间值的文本表示时静默应用JVM当前默认时区的不幸行为。我这里的JVM的默认时区为America/Los_Angeles。因此调整了一天中的时间(令人困惑)。

java.time框架内置在Java8及更高版本中。这些类取代了麻烦的旧遗留日期-时间类,如java.util.DateCalendar

Joda Time项目现在处于维护模式,建议迁移到java。时间课。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR 310。

使用符合JDBC 4.2或更高版本的JDBC驱动程序,您可以交换java。时间对象直接与数据库连接。不需要字符串或java。sql.*上课。

在哪里可以获得java。时间课?

  • JavaSE 8,JavaSE 9,以及更高版本
    • 内置。
    • 标准的一部分Java带有捆绑实现的API。
    • Java9增加了一些次要功能和修复。
    • java的大部分内容。时间功能被重新移植到Java 6
    • 更高版本的Android捆绑包java实现。时间课
    • 对于早期的Android,ThreeTenABP项目采用了ThreeTen Backport(如上所述)。了解如何使用ThreeTenABP

    额外的Three Ten项目扩展了java。有额外课程的时间。这个项目是java未来可能增加的一个试验场。时间你可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,等等。

况经纬
2023-03-14

我真的无法评估你的理解,但我的理解是:

时间戳类继承自日期。日期——与您从Javadoc中引用的内容一致——只是一个长值的包装。发生的情况是,字符串被转换为时间值(不知何故——如果你想分享你的机制,请更新代码片段)。这隐式或显式地使用了时区,但结果long值独立于时区,与调用系统时相同。currentTimeMillis()位于给定时间转换中使用的时区中。如果要控制用于转换的时区,可以使用SimpleDataFormat并按如下方式设置时区:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
  simpleDateFormat.parse("2016-01-08 08:03:52.0");
} catch (ParseException e) {
  // handle the error here
}

在您的编辑之后(缺少函数dateInLong的定义),我创建了以下测试类,其中我添加了一些控制台输出:

public class test {
  @Test
  public void test() throws ParseException {
    Calendar curCal = new GregorianCalendar(TimeZone.getDefault());
    curCal.setTimeInMillis(System.currentTimeMillis());
    System.out.println("curCal 1:   " + curCal.getTimeInMillis());

    TimeZone fromTz = TimeZone.getDefault();
    curCal.setTimeZone(fromTz);
    System.out.println("curCal 2:   " + curCal.getTimeInMillis());

    TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
    Calendar toCal = new GregorianCalendar(gmtTZ);
    toCal.setTimeInMillis(curCal.getTimeInMillis());

    Date dd = toCal.getTime();
    System.out.println("dd:         " + dd.getTime());
    SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a", Locale.US);
    format.setTimeZone(gmtTZ);
    String ff = format.format(dd);

    long time = dateInLong(ff, "dd/MM/yyyy hh:mm:ss a");
    System.out.println("time:       " + time);
    java.sql.Timestamp curTimeInGMT = new java.sql.Timestamp(time);
    System.out.println("curTimeGMT: " + curTimeInGMT.getTime());
  }

  private long dateInLong(String dateString, String formatStr) throws ParseException {
    SimpleDateFormat format = new SimpleDateFormat(formatStr);
    return format.parse(dateString).getTime();
  }
}

它产生以下输出:

curCal 1:   1452603245943
curCal 2:   1452603245943
dd:         1452603245943
time:       1452599645000
curTimeGMT: 1452599645000

如您所见,内部long值发生变化的唯一情况是,由于使用了两个不同的时区(到String:GMT,从String:default到CET),日期被转换为字符串(即在调用dateInLong之后)。只要传递内部的long值,时间时刻就会保持不变——不管它是由日历还是日期的后代包装的。

 类似资料:
  • 本文向大家介绍sqlite时间戳转时间语句(时间转时间戳),包括了sqlite时间戳转时间语句(时间转时间戳)的使用技巧和注意事项,需要的朋友参考一下 下面是具体的实现代码:

  • 我知道这是一个非常常见的问题,但我觉得我找到的答案并没有真正解决问题。我将概述我的具体用例,并对来自其他SO答案和网络的信息进行总结。 对于我正在编写的服务,数据库条目被创建并存储在移动设备和我们的网站上,需要以两种方式同步。我们目前的目标是Android和iOS,它们都使用sqlite作为关系数据库。服务器端是使用Django和MySQL在Python中实现的,但将来可能会有其他解决方案取代它。

  • 问题内容: 我正在使用MongoDB来存储我的数据。Mongo默认将时间戳存储在UTC中。我们在不同时区处理数据。我正在努力将UTC时间戳转换为PDT或IST时间戳。 试图构造一种方法来传递时区(将我的时间戳转换为时区)和timestamp(UTC)。返回指定时区的时间戳的方法。 问题答案: 您可以使用带有所需时区的dateformat并将其应用于日期

  • 返回我女巫是错误的。 但接下来的查询如下: 我看对日期

  • 我想将时间戳转换为。 这是我到目前为止已经实现的,但是它给了我错误的月份 任何帮助将不胜感激。

  • 我有一个Flink程序,它接受两个流,即数据/传感器读数流和警报规则流。我正在广播规则流,并将其连接到数据流以生成动态警报。ProcessingTime的一切都很好,但EventTime却不行。我已经分配了时间戳 > 当两个流(即带有时间戳的流)同时出现时,如何使用“EventTime”生成警报 我是否也必须为我的规则流分配时间戳和水印? 因为我的规则流只有在有任何添加/修改时才会有记录。是否有任