我正在尝试将UTC日期转换为IST。但令我惊讶的是,在转换所有内容后,它仍然只返回我的 UTC。怎么可能?
输入:
StartDateTimeUtc='2017-09-15T14:00:00',
EndDateTimeUtc='2017-09-15T15:00:00'
法典:
public static final String DATE_FORMATE_CURRENT = "yyyy-MM-dd'T'HH:mm:ss";
Date meetingStartDate = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(model.StartDateTimeUtc);
Date meetingEndDate = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(model.EndDateTimeUtc);
//Convert Date to String
DateFormat df = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT);
String meetinStartDateString = df.format(meetingStartDate);
String meetingEndDateString = df.format(meetingEndDate);
//Convert String Date to IST
SimpleDateFormat dftwo = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT);
dftwo.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date = null;
Date datetwo = null;
try {
date = dftwo.parse(meetinStartDateString);
datetwo = dftwo.parse(meetingEndDateString);
} catch (ParseException e) {
e.printStackTrace();
}
dftwo.setTimeZone(TimeZone.getDefault());
String formattedStartDate = dftwo.format(date);
String formattedEndDate = dftwo.format(datetwo);
//Convert String Date back to Date format so that we can pass into Calendar code
Date meetingStartDateFinal = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(formattedStartDate);
Date meetingEndDateFinal = new SimpleDateFormat(Constants.DATE_FORMATE_CURRENT, Locale.ENGLISH).parse(formattedEndDate);
再次以 UTC 格式输出:
Start Date : Fri Sep 15 14:00:00 GMT+05:30 2017
End Date : Fri Sep 15 15:00:00 GMT+05:30 2017
java.util.Date
没有任何时区信息。它只包含一个值:自 unix 纪元(1970-01-01T00:00Z
年,或 1907 年 1 月 1 日,UTC午夜)以来的毫秒数。
这个毫秒数在世界各地都是一样的。不同的是每个时区中的相应日期和时间。示例:现在,此米利斯值为1505481835424
,在 UTC 中对应于2017-09-15T13:23:55.424Z
。此值对应于圣保罗的 10:23 AM、加尔各答的 18:53、伦敦的 14:23 等。每个时区的本地日期/时间都不同,但每个人的 millis 值都相同。
这就是为什么你不转换Date
本身:米利斯值是相同的,没有必要改变它。您可以更改的是此日期在不同时区中的表示形式。
SimpleDateFormat
,默认情况下,使用 JVM 默认时区来解析日期。但是,如果您知道输入位于特定区域,则必须在格式化程序中进行设置。因此,要解析您的输入,您必须执行以下操作:
String startDateTimeUtc = "2017-09-15T14:00:00";
String endDateTimeUtc = "2017-09-15T15:00:00";
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss");
// input is in UTC
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// parse dates
Date meetingStartDate = sdf.parse(startDateTimeUtc);
Date meetingEndDate = sdf.parse(endDateTimeUtc);
上面的 2 个Date
对象将对应于 14:00 和 15:00 UTC(与加尔各答时区的 19:30 和 20:30 相同)。
但是,如果您只是直接打印Date
对象(使用System.out.println
、日志记录,甚至在调试器中检查它们的值),它将隐含调用toString()
方法,该方法在幕后使用 JVM 默认时区,从而产生您看到的输出(Fri Sep 15 14:00:00 GMT+05:30 2017
)。
如果要以特定格式和特定时区打印,则需要其他格式化程序:
// another formatter for output
SimpleDateFormat outputFormat= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
// output will be in Asia/Kolkata timezone
outputFormat.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
System.out.println(outputFormat.format(meetingStartDate));
System.out.println(outputFormat.format(meetingEndDate));
输出将是:
2017-09-15T19:30:002017-09-15T20:30:00
这对应于加尔各答时区的相同 UTC 日期。
请记住:您不会在时区之间转换Date
(因为它们的米利斯值是"绝对的" - 它们对世界上的每个人都是一样的)。您只需更改这些日期的String
表示形式(特定时区中的相应日期/时间)。
Java 新的日期/时间 API
旧的类(Date
、Calendar
和SimpleDateFormat
)有很多问题和设计问题,它们正在被新的API所取代。
在Android中,你可以使用ThreeTen Backport,这是Java 8新的日期/时间类的一个很好的反向移植。要使其正常工作,您还需要ThreeTenABP(有关如何使用它的更多信息) 这里).
这个新的 API 针对每种情况都有许多不同的日期/时间类型。在这种情况下,输入有日期和时间,但没有时区信息,所以首先我使用org.threeten.bp.format.DateTimeFormatter
将它们解析为org.threeten.bp.LocalDateTime
:
// parse the inputs
DateTimeFormatter fmt = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime startDt = LocalDateTime.parse(startDateTimeUtc, fmt);
LocalDateTime endDt = LocalDateTime.parse(endDateTimeUtc, fmt);
然后我使用org.threeten.bp.ZoneOffset
将它们转换为 UTC,然后使用org.threeten.bp.ZoneId
将其转换为另一个时区。结果将是一个org.threeten.bp.ZonedDateTime
:
// input is in UTC
ZoneOffset utc = ZoneOffset.UTC;
// convert to Asia/Kolkata
ZoneId zone = ZoneId.of("Asia/Kolkata");
ZonedDateTime start = startDt.atOffset(utc).atZoneSameInstant(zone);
ZonedDateTime end = endDt.atOffset(utc).atZoneSameInstant(zone);
然后我使用相同的DateTimeFormatter
来格式化输出:
System.out.println(fmt.format(start));
System.out.println(fmt.format(end));
输出为:
2017-09-15T19:30:002017-09-15T20:30:00
请注意,我不需要在格式化程序中设置时区,因为时区信息在对象中(它们负责进行转换)。