2017-09-13 32 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解决方案,但它不工作:( –