我从设备上的以下代码行中获取了时区4小时的时差:
我正在以2018-09-30T13:45:00Z
这样的方式度过时间
我的开始和结束日期如下:-
“ start_date”:“ 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 );
问题:当我将时区设置为BOSTON(US)时,从上述代码获取了4个小时的时间差,出现错误。
我从下面的@Hugo解决方案得到的结果如下
我期待如下结果
请检查一次。.我还设置了美国东部夏令时间的时区,但未获得适当的解决方案。请检查一次。并让我知道
最佳答案
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的格式化程序来解析它。因此,不要使用c.getTimeZone()
和TimeZone.getDefault()
,而应仅使用TimeZone.getTimeZone("UTC")
。对于输出,必须将格式器设置为要转换为时区的格式。如果时区为“ 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”)。这是因为more than one timezone使用了“ EDT”,因此必须特别选择要使用的那个(在这些示例中,我使用的是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 AM 09:45 AM
Java新的日期/时间API
旧的类(
Date
,Calendar
和SimpleDateFormat
)具有lots of problems和design issues,它们已被新的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
等同于EEEE
,并打印全名),而语言环境则定义所使用的语言。最后,要获取相应的时间,可以使用另一个
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()
),只需在检查它的值之前确保它是您想要的值(这可能不是因为可以在运行时更改它,所以始终最好指定一个值) 。
关于android - 在将数据转换为设备时区的同时获得4个小时的时间差?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46200941/