2016-01-08 53 views
1

可以说我有一个时间戳记值。Timestamp.getTime()将时间戳值视为系统时区中的时间

编辑

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()以上时间的毫秒值;在的getTime()方法,按照Java文档的

Long l = t.getTime(); 

定义是 Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Timestamp object.

所以,从我通过测试了这么多次了解,getTime()将会给给定的时间和月份之间的毫秒差1,1970,00:00:00 GMT。

对于getTime()与1970年1月1日00:00:00格林威治时间差异,它需要另一个GMT时间。 所以它需要将给定时间转换为GMT时间。对于该转换,它需要给定时间的时区。 它会考虑给定时间的时区为系统时区,它会得到相应的GMT时间,然后它会找到两个GMT时间之间的差异,它会返回差异。

我的理解是否正确?

+0

显示的内容不是时间戳,而是时间戳的字符串表示形式......答案完全取决于您如何创建实际时间戳。 – assylias

+0

为了理解,我只是复制了存储在表中的时间戳值以将其放在此处。 – Matchendran

+2

什么表?在数据库表中?数据库列的类型是什么?等你需要提供更多的信息.​​.. – assylias

回答

1

我真的不能评估你的理解,但这里是我的:

Timestamp类日期从继承。日期 - 与您从Javadoc引用的内容一致 - 只是长期价值的包装。会发生什么是字符串转换(不知何故 - 请更新代码片段,如果你想分享你的机制)的时间值。这隐式地或明确地使用了一个时区,但生成的long值与时区无关,与在给定时间在转换中使用的时区中调用System.currentTimeMillis()时相同。如果要控制用于转换的时区,你可以使用一个SimpleDateFormat和设置时区,如下所示:

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 

正如你可以发我在其中添加了一些控制台输出以下测试类ee,内部长值变化的唯一场合是日期转换为字符串和从字符串转换(即在调用dateInLong之后),即由于使用两个不同的时区(字符串:格林尼治标准时间,从字符串:默认 - CET在这里)。只要您传递内部长整型值,不管是否包含CalendarDate的后代,时刻都保持不变。

+0

没问题,我只希望我的回答有助于澄清问题。 –

+0

对不起,这个时间戳值。我复制了存储在表中的时间,并粘贴在这里给予理解。我们没有像这样宣布时间戳值。我的疑问很简单。当我们调用getTime()时,它会在内部将给定时间转换为GMT时间,并获得差异 ,或者只是将给定时间视为GMT时间并获得差异。 因为要找到一个格林威治时间的差异,它需要另一个GMT时间 – Matchendran

+2

'getTime()'不执行任何转换,它只是返回长vlaue。另外,没有与'Date'和'TimeZone'关联的TZ。同样,如果你可以分享你如何得到'TimeZone'实例,这可能会有所帮助。 –

0

两点都会使这项工作更容易:

与日期时间
  • 工作对象,而不是字符串。
    您应该使用JDBC来提取java.sql。来自数据库的时间戳对象,而不是那些日期时间值的字符串表示。
  • 使用Java 8及更高版本中内置的java.time框架。
    避免使用旧的java.util.Date/.Calendar类。

首先,我们必须指定一个格式器来解析您的输入字符串,或者将其改为符合默认情况下在java.time中使用的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.Timestamp对象,被发送到数据库中。那个旧类有一个新的方法,用于转换为java.time对象。转换需要一个Instant对象,这是UTC时间轴上的一个时刻。我们可以从我们的ZonedDateTime中提取Instant

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年1月8日08:03:在ISO 8601 52.0:2016-01-08T08:03:52.0是localDateTime:2016-01-08T08:03:52在了zoneid:美国/蒙特利尔是zdt:2016-01-08T08:03:52-05:00 [America/Montreal]给予即时:2016-01-08T13:03:52Z转换为java.sql.Timestamp ts:2016-01-08 05:03:52.0

仔细阅读控制台输出。请注意0​​上的时间。这显示java.sql.Timestamp方法toString在生成日期时间值的文本表示时静默应用JVM的当前默认时区的不幸行为。我的JVM默认时区为America/Los_Angeles。所以时间被调整(令人困惑)。


关于java.time

java.time框架是建立在Java 8和更高版本。这些类代替了日期时间类legacy,如java.util.Date,Calendar,& SimpleDateFormat

Joda-Time项目,现在在maintenance mode,建议迁移到java.time类。请参阅Oracle Tutorial。并搜索堆栈溢出了很多例子和解释。规格是JSR 310

随着JDBC driverJDBC 4.2或更高版本相符时,你可以交换java.time直接对象与数据库。无需字符串或java.sql。*类。

从哪里获取java.time类?

ThreeTen-Extra项目与其他类扩展java.time。这个项目是未来可能增加java.time的一个试验场。您可以在这里找到一些有用的类,如Interval,YearWeek,YearQuartermore