Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Timestamp.getTime()将时间戳值视为系统时区中的时间_Java_Timezone_Timestamp - Fatal编程技术网

Java Timestamp.getTime()将时间戳值视为系统时区中的时间

Java Timestamp.getTime()将时间戳值视为系统时区中的时间,java,timezone,timestamp,Java,Timezone,Timestamp,假设我有一个时间戳值 编辑 Calendar curCal = new GregorianCalendar(TimeZone.getDefault()); curCal.setTimeInMillis(System.currentTimeMillis()); TimeZone fromTz = TimeZone.getDefault(); curCal.setTimeZone(fromTz); TimeZone

假设我有一个时间戳值

编辑

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()
获取上述时间的毫秒值

根据Java文档,getTime()方法的定义如下
返回此时间戳对象表示的自1970年1月1日00:00:00 GMT以来的毫秒数。

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

要获得1970年1月1日00:00:00 GMT的差值,需要另一个GMT时间。 因此,它需要将给定的时间转换为格林尼治标准时间。对于这种转换,它需要给定时间的时区。 将给定时间的时区视为<强>系统时区< /强>,并得到相应的GMT时间,然后找出两个GMT时间的差值,并返回差值。


我的理解正确吗?

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

时间戳类继承自日期。日期——与您从Javadoc引用的内容一致——只是一个长值的包装。发生的情况是字符串被转换为时间值(不知何故-如果您想共享您的机制,请更新代码片段)。这隐式或显式地使用时区,但生成的long值独立于时区,与在给定时间在转换中使用的时区中调用
System.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值,时间时刻就会保持不变—不管它是由
日历
包装还是由
日期
的后代包装。

两点将使这项工作更加容易:

  • 使用日期时间对象而不是字符串。
    您应该使用JDBC从数据库中提取java.sql.Timestamp对象,而不是这些日期时间值的字符串表示形式
  • 使用java 8及更高版本中内置的java.time框架。
    避免使用旧的java.util.Date/.Calendar类
首先,我们必须指定一个格式化程序来解析输入字符串,或者修改它以满足java.time中默认使用的标准。ISO 8601格式接近SQL格式,用“<代码> t>代码>替换中间的空间。

String input = "2016-01-08 08:03:52.0";
String inputIso8601 = input.replace ( " ", "T" );
将该字符串解析为本地日期时间,这意味着任何位置。输入字符串缺少任何时区或UTC信息的偏移量,因此我们从本地开始,然后应用假定的时区

LocalDateTime localDateTime = LocalDateTime.parse ( inputIso8601 );
让我们应用假定的时区。我随意选择Montréal,但显然,您需要知道并使用该字符串输入的任何时区。如果您确定该字符串表示UTC,请使用
ZoneOffset.UTC

ZoneId zoneId = ZoneId.of ( "America/Montreal" ); // Or perhaps ZoneOffset.UTC constant.
ZonedDateTime zdt = ZonedDateTime.of ( localDateTime, zoneId );
现在我们准备转换成
java.sql.Timestamp
对象,发送到数据库。这个旧类有一个新方法,用于转换java.time对象。转换需要一个
即时
对象,它是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 );
输入:ISO 8601:2016-01-08T08:03:52.0中的2016-01-08 08:03:52.0是localDateTime:2016-01-08T08:03:52在zoneId:America/Montreal中是zdt:2016-01-08T08:03:52-05:00[美国/蒙特利尔]给出即时: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.time对象。不需要字符串或java.sql.*类

从哪里获得java.time类

  • ,及以后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类
    • 对于早期的Android,该项目采用了ThreeTen Backport(如上所述)。看

该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,例如、、和。

您显示的不是时间戳,而是ti的字符串表示形式
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 );