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