2016-11-02 80 views
1

我正在逐行處理文件。轉換日期在dst中一小時

的每一行都具有以下列格式的日期:YYMMDD HHMM

該文件被基本上記錄讀取每隔15分鐘。該錄製使用的是節省時間的日光。我遇到的問題是在春季前進和後退。記錄是複製發生回退的日期和發生回退時的間隔。

後備例如:

141102 0 115 - 複製

141102 0130 - 複製

141102 0145 - 複製

141102 0200 - 複製

春天正向例如:

我需要做的是在夏令時期間將所有日期向前移動一個小時。

我正在使用的程序目前正在使用java.util.Calendar。我已經嘗試使用java日曆進行轉換,並且遇到了很多添加日期的問題。我認爲問題在於它正在嘗試糾正DST問題本身,當我想要做的就是將日期轉換一小時。它還有一個檢測差距的問題。例如,它認爲,第一個1:15 - 2:00是在白天,當這不是情況。

基本上我想要的是後備例如更改爲在此日期範圍內下降到移回一小時的一切:

後備例如:

141102 0100沒有變化

141102 0115無變化

141102 0130無變化

1 41102 0145沒有變化

141102 0200沒有變化

141102 0115至141102 0215

141102 0130至141102 0230

141102 0145至141102 0245

141102 0200至141102 0300

保持更改日期,直到它彈出前進

150308 0200至150308 0300

150308 0315沒有變化。

我嘗試了很多方法,似乎無法找到解決方案。我不反對使用喬達時代,因爲我一直在研究這一點。任何幫助將不勝感激,謝謝。

+0

所以你真正想要做的是將日期轉換爲一個文件名,使用的時區在夏天不會改變它的偏移量,對吧? –

+0

它不是文件名,而是文件中有'timestamp'的一行。我想在dst的一個小時內轉換該時間戳,以便我沒有缺口或重複的條目。 – DHines

+2

好的,但不會只使用日期格式沒有夏時制的時區達到那個目的?或者我錯過了什麼?標準做法是在日誌文件中使用UTC作爲時間戳,但大概您更希望在冬天您的時區與您的時區保持一致。 –

回答

2

UTC

始終使用UTC進行數據交換和這種讀數記錄。始終,始終使用UTC。將UTC視爲一個真實時間和其他時區與UTC的偏差。

順便說一句,Daylight Saving Time (DST)不是唯一的問題是擔心區劃日期時間值。其他異常發生在各個時區,導致wall-clock time向前或向後移動。解決方案很簡單:避免使用所有時區 - 使用UTC

Instant

Instant類捕獲UTC時間線與納秒的分辨率上一會兒。這應該是你去上課的日期時間工作。

Instant instant = Instant.now(); 

字符串

用於記錄,生成標準ISO 8601格式的字符串。堅持採用經過驗證的ISO 8601格式,而不是發明自己的產品。

包括Instant的java.time類在解析/生成字符串時默認使用ISO 8601格式。所以不需要指定格式化模式。

String output = instant.toString(); 

2016-11-02T21:10:05.321Z

Instant instant = Instant.parse("2016-11-02T21:10:05.321Z"); 

而且始終在您的日期世紀20。忽略只會爲錯誤解釋中的錯誤創造很多機會。存儲和內存真的很便宜,我們可以負擔兩個額外的數字。

時區指針

始終包括時區或偏移從-UTC指標與序列化日期時間值。

在上面看到的Instant::toString結果中,Z代表Zulu,表示UTC。

解析字符串

下面是代碼來解析您的日期時間字符串。我們首先解析爲LocalDateTime,沒有任何時區或偏移量,因爲您的輸入缺少任何時區或偏移量的指示符。然後我們分配一個時區來獲得ZonedDateTime,以瞭解它如何處理DST切換的時刻。

我認爲問題所在時區使用凌晨2點的DST回退割接。作爲這樣的例子,我使用America/Montreal

List<String> inputs = new ArrayList<>(2); 
inputs.add("141102 0115"); // 1 AM 
inputs.add("141102 0215"); // 2 AM 

for(String input : inputs) { 
    DateTimeFormatter f = DateTimeFormatter.ofPattern("uuMMdd HHmm"); 
    LocalDateTime ldt = LocalDateTime.parse(input , f); 

    // At 2 AM in this zone, the clock falls back one hour for DST cutover. The 1 AM hour repeats. 
    ZoneId z = ZoneId.of("America/Montreal"); 
    ZonedDateTime zdt = ldt.atZone(z); 

    System.out.println("input: " + input); 
    System.out.println("ldt: " + ldt); 
    System.out.println("zdt: " + zdt); 
    System.out.println("instant: " + zdt.toInstant()); 
    System.out.println(""); 
} 

輸入:141102 0115

LDT:2014-11-02T01:15

ZDT:2014-11-02T01:15-04:00 [美國/蒙特利爾]

瞬間:2014-11-02T05:15:00Z

......還有......

輸入:141102 0215

LDT:2014-11-02T02:15

ZDT:2014-11-02T02:15-05:00 [美國/蒙特利爾]

瞬間: 2014-11-02T07:15:00Z

您可以see this code live in IdeOne.com。請注意UTC值的兩小時差異(Z)。

我們看到的行爲被記錄在案。

在大多數情況下,本地日期時間只有一個有效偏移量。在時鐘重新設置的情況下,有兩個有效的偏移量。此方法使用通常對應於「夏季」的較早的偏移量。

上午1點15分含糊不清,可能是第一或第二次出現java。時間與第一次一樣。

你可以玩猜謎遊戲來嘗試調整這些糟糕設計的字符串。如果您確定在每個時鐘小時內至少有一個樣本,則可以跟蹤以前的樣本並查看正在處理的樣本是否比以前的時鐘早。如果是這樣,你可以認爲這是一個DST後退切換,並添加一小時plusHours(1)

if(processingZdt.toLocalDateTime().isBefore(previousZdt.toLocalDateTime()) { 
    processingZdt.plusHours(1) ; // A hack; I am *not* recommending this. 
    … 

但是,這是一個解決方案的冒險攻擊。我不確定這項工作,因爲我沒有想到它通過。如果絕望,也許你可以讓它工作。

明智的做法是預防:使用UTC

+0

謝謝,這是對我的回答很好的迴應,並且對未來如何做到這一點非常有幫助。問題是我正在做一個15年前創建的程序,現在他們想要添加它,並且我在java.util.Calendar類中綁定了它們,因爲它們在整個程序中都使用它。 – DHines

+0

@DHines你可以[轉換](http://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html#toZonedDateTime--)一個'GregorianCalendar'到'ZonedDateTime'並提取UTC的「即時」。 'ZonedDateTime zdt = myGregCal.toZonedDateTime();'查看[這個問題](http://stackoverflow.com/q/36639154/642706)獲取更多關於轉換的信息。遺留的日期 - 時間類真的很麻煩,應該避免。這就是Sun和Oracle同意發明java.time的原因。 –

+0

感謝您提供該問題的鏈接。這是有見地的,我認爲會有所幫助。我不確定它100%是否解決了我的問題。文件進入的方式有兩個輸入141102 0115時會有重複的日期,並且當它們有彈簧前進時(即輸入150308 0200和150308 0315)會有重複的日期。我不能改變文件的方式,我必須處理它。所以我想我正試圖完成的是當我在第一時間需要將所有數據轉移一小時時。 – DHines