SimpleDateFormat
和Calendar
使用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:00Z
:Z
最後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_York
或Europe/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
,Calendar
和SimpleDateFormat
)有lots of problems和design 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.ENGLISH
或javadoc中所述的任何其他值)。
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()
),只需在之前檢查它的值以確保它是您想要的值(可能不是因爲它可以在運行時更改,所以最好指定一)。
'TimeZone.getDefault()。getDisplayName()'的價值是什麼? '2018-09-30T13:45:00Z'是輸入'String'嗎?你得到的輸出和預期的輸出是什麼? – 2017-09-13 15:42:44
@ Hugo..Will發佈我的輸出和明天的預期輸出..現在我離開辦公室 –
嗯,我已經發布了一個答案。如果這不是你所需要的,只是讓我知道,我會相應地更新它。 – 2017-09-13 17:34:39