2017-09-13 73 views
1

我正在上時區4小時區別從下面我的設備上的代碼行:將數據轉換爲設備時區時獲得4小時差異?

我收到時間以這樣的方式像2018-09-30T13:45:00Z

我開始和結束日期是如下: -

「起始日期」: 「2017-09-13T12:15:00Z」
「END_DATE」: 「2018-09-30T13:45:00Z」

Calendar c = Calendar.getInstance(Locale.getDefault()); 
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss"); 
formatter.setTimeZone(TimeZone.getTimeZone("UTC")); 
Date localStartDate = formatter.parse(startTime); 
Date localEndDate = formatter.parse(endTime); 
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm"); 

dateFormatter.setTimeZone(c.getTimeZone()); 
localStartDate = dateFormatter.parse(startTime); 
localEndDate = dateFormatter.parse(endTime); 
SimpleDateFormat monthFormat = new SimpleDateFormat("MMM"); 
monthFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getDisplayName())); 


String monthName = monthFormat.format(localStartDate); 
eventDate.setMonth(monthName); 
SimpleDateFormat dateFormat = new SimpleDateFormat("dd"); 
dateFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getDisplayName())); 


String dateName = dateFormat.format(localStartDate); 
eventDate.setDate(dateName); 
SimpleDateFormat dayNameFormat = new SimpleDateFormat("EEEE"); 
dayNameFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getDisplayName())); 


String dayName1 = dayNameFormat.format(localStartDate); 
String dayName2 = dayNameFormat.format(localEndDate); 
eventDate.setDayName1(dayName1); 
eventDate.setDayName2(dayName2); 
SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm a"); 
timeFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getDisplayName())); 



String startTimeName = timeFormat.format(localStartDate); 
String endTimeName = timeFormat.format(localEndDate); 


System.out.println("My Start date and end date==>>>"+startTimeName+" " +endTimeName); 

問題:從上面的代碼中獲得4小時的差異,因爲我將時區設置爲BOSTON(US),出現錯誤。

我的結果從下面的@Hugo解決方案如下 enter image description here

,我期待的結果如下 enter image description here

請檢查once..I也有設置時區爲東部白天時間但沒有得到正確的解決方法。請檢查一次..並讓我知道

+1

'TimeZone.getDefault()。getDisplayName()'的價值是什麼? '2018-09-30T13:45:00Z'是輸入'String'嗎?你得到的輸出和預期的輸出是什麼? – 2017-09-13 15:42:44

+0

@ Hugo..Will發佈我的輸出和明天的預期輸出..現在我離開辦公室 –

+0

嗯,我已經發布了一個答案。如果這不是你所需要的,只是讓我知道,我會相應地更新它。 – 2017-09-13 17:34:39

回答

2

SimpleDateFormatCalendar使用JVM默認時區(除非您在其上設置了不同的時區),並且每個設備/機器/環境中的默認時區可以不同。不僅如此,這個默認can be changed without notice, even at runtime,所以最好總是明確你正在使用哪一個。

當你做這樣的事情:

Calendar c = Calendar.getInstance(Locale.getDefault()); 
dateFormatter.setTimeZone(c.getTimeZone()); 
monthFormat.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getDisplayName())); 

Calendar使用默認時區創建的,所以dateFormatter也會有相同的區域。 monthFormat也是你創建的其他格式化程序。唯一的格式化程序設置爲不同的區域是第一個(設置爲UTC)。

此外,第二個格式化程序是多餘的(它與第一個格式化程序的功能相同,即將String解析爲Date),因此您可以將其刪除。

假設您的輸入是String,其值爲2018-09-30T13:45:00ZZ最後indicates that this date is in UTC。所以你應該用解析它使用格式化程序設置爲UTC。因此,您應該只使用TimeZone.getTimeZone("UTC"),而不是使用c.getTimeZone()TimeZone.getDefault()

對於輸出,你必須要轉換的時區設置格式化。如果時區爲「EDT」,則設置爲(但不要完全使用「EDT」,見下文)。如果您想使用JVM默認值,請使用TimeZone.getDefault()-只需在之前檢查此值,以確保默認值是您需要的值

請記住,像「EDT」和「EST」這樣的短名稱不是實時時區。這些縮寫是ambiguous and not standard。傾向於使用IANA timezones names(總是採用格式Region/City,如America/New_YorkEurope/Berlin)。

因此,當你做TimeZone.getTimeZone("EDT")it usually returns "GMT"(因爲「EDT」未被識別,並且「GMT」被作爲默認返回)。這是因爲「EDT」由more than one timezone使用,所以您必須具體選擇使用哪一個(在這些示例中,我使用America/New_York)。

另一個細節是,在前2個格式化程序中,您使用hh,which means "hour of am/pm"(值從1到12),但輸入沒有AM/PM指示符來正確解決此問題。您需要將其更改爲HH(「每小時」,值爲0到23)。

// input is in UTC 
TimeZone inputZone = TimeZone.getTimeZone("UTC"); 
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); 
formatter.setTimeZone(inputZone); 
Date localStartDate = formatter.parse(startTime); 
Date localEndDate = formatter.parse(endTime); 
... 

// removed the second formatter (it was redundant) 

// output is in EST (America/New_York) 
// or use TimeZone.getDefault() to get JVM default timezone 
TimeZone outputZone = TimeZone.getTimeZone("America/New_York"); 
SimpleDateFormat monthFormat = new SimpleDateFormat("MMM"); 
monthFormat.setTimeZone(outputZone); 
... 

SimpleDateFormat dateFormat = new SimpleDateFormat("dd"); 
dateFormat.setTimeZone(outputZone); 
... 

SimpleDateFormat dayNameFormat = new SimpleDateFormat("EEEE"); 
dayNameFormat.setTimeZone(outputZone); 
... 

SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm a"); 
timeFormat.setTimeZone(outputZone); 
... 

System.out.println("My Start date and end date==>>>" + startTimeName + " " + endTimeName); 

由此,你顯式使用輸入和輸出的特定時區UTC,而不是依賴於在JVM默認時區(其可以是在每個裝置中不同,並且你無法控制)。

輸出是:

我的開始日期和結束日期== >>> 08:15上午上午9時45分


新的Java日期/時間API

舊的類(Date,CalendarSimpleDateFormat)有lots of problemsdesign issues,它們被替換爲th新的API。

在Android中,您可以使用ThreeTen Backport,它是Java 8新日期/時間類的一個很好的後端。爲了使它的工作,你還需要在ThreeTenABP(關於如何使用它here更多)。

首先,您可以使用org.threeten.bp.Instant來解析輸入,因爲它採用UTC(最終由Z指定)。然後,使用一個org.threeten.bp.ZoneId將其轉換爲一個org.threeten.bp.ZonedDateTime

// output timezone 
// or use ZoneId.systemDefault() to get JVM default timezone 
ZoneId zone = ZoneId.of("America/New_York"); 
// parse the inputs 
ZonedDateTime startDate = Instant.parse(startTime).atZone(zone); 
ZonedDateTime endDate = Instant.parse(endTime).atZone(zone); 

然後你就可以使用這些對象,以獲得其他領域:

// get month name 
System.out.println(startDate.getMonth().getDisplayName(TextStyle.SHORT, Locale.getDefault())); 

這相當於MMM模式,它將打印月份名稱在默認區域設置中。如果您想要使用特定語言的月份名稱,只需使用另一個java.util.Locale值(例如Locale.ENGLISHjavadoc中所述的任何其他值)。

org.threeten.bp.format.TextStyle定義月份名稱是否會縮小(通常只是一個字母),簡寫(通常是2或3個字母)或全部(全名)。輸出根據使用的語言環境而變化。

我個人更喜歡不使用默認語言環境,因爲即使在運行時它也可以在不通知的情況下進行更改。指定所需的語言環境總是更好。

要獲得一個月的一天,你可以選擇把它作爲一個int或格式化String(使用org.threeten.bp.format.DateTimeFormatter):

// get day of month as int 
int day = startDate.getDayOfMonth(); // 30 
// get day of month as formatted string 
String dayStr = DateTimeFormatter.ofPattern("dd").format(startDate); // 30 

要獲得一週的某一天,它是相似的代碼用於獲取月:

// get day of week 
System.out.println(startDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())); 

同樣的邏輯也適用於這裏:在TextStyle定義的名字怎麼會(在這種情況下,FULL是equivalen到EEEE,並印刷在F ull名稱),並且語言環境定義使用的語言。

最後,得到相應的時間,你可以使用另一個DateTimeFormatter

// get time 
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("hh:mm a"); 
System.out.println(fmt.format(startDate)); // 08:15 AM 
System.out.println(fmt.format(endDate)); // 09:45 AM 

這將日期/時間在你選擇用於輸出的時區。

如果您打算使用JVM默認值(ZoneId.systemDefault()),只需在之前檢查它的值以確保它是您想要的值(可能不是因爲它可以在運行時更改,所以最好指定一)。

+0

感謝您的解決方案..它是'不'爲我工作..我已編輯的問題,請檢查一次..我已經完成了代碼,因爲你建議。但現在我得到的時間+4小時..請幫助我 –

+0

我已經使用[鏈接](https://github.com/JakeWharton/ThreeTenABP)但沒有得到解決方案,請檢查一次。 –

+0

請幫助我,我已經嘗試過urs解決方案,但它不工作:( –