2016-01-08 91 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