我正在研究一些处理时区差异的代码(在这种情况下,将日期从UTC转换为EST / EDT)我注意到我得到了错误的DATE
来自Calendar
变量的字段。
以下是时区变更的日志摘录:
UTC time: Fri Nov 15 00:28:44 EST 2013
America/New_York time: Thu Nov 14 19:28:44 EST 2013
根据Calendar.getTime()
显示的内容,代码正确地将时间更新为14日,但是当我致电Calendar.get(Calendar.DATE)
时,我仍然将15作为日期。
为什么时间本身不会更新字段?
代码摘录:
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
TimeZone fromTz = TimeZone.getTimeZone("UTC");
TimeZone toTz = TimeZone.getTimeZone("America/New_York");
jlog.info(fromTz.getID() + " time: " + cal.getTime().toString());
cal.setTimeZone(fromTz);
// Finds the difference between the two timezones based on their offset from UTC (in the case of the system timezone changing in the future).
long currentTime = System.currentTimeMillis();
int timeDifference = toTz.getOffset(currentTime) - fromTz.getOffset(currentTime);
cal.add(Calendar.MILLISECOND, timeDifference);
if (dst) { // Logic for determining whether or not the extra hour for DST is needed.
cal.add(Calendar.MILLISECOND, fromTz.getDSTSavings());
}
jlog.info(toTz.getID() + " time: " + cal.getTime().toString());
jlog.info(cal.getTime().toString() + " - " + cal.get(Calendar.DATE));
以上代码的输出:
UTC time: Fri Nov 15 00:28:44 EST 2013
America/New_York time: Thu Nov 14 19:28:44 EST 2013
Thu Nov 14 19:28:44 EST 2013 - 15
注意:请不要建议我使用Joda-time。我只是按原样寻找这个问题的答案。
如果因为日历/日期是糟糕的套餐而无法解决,那很好 - 我只是自己解析日期以获得正确的值。提前谢谢。
答案 0 :(得分:4)
您没有向我们展示足够的代码来了解正在发生的事情,但您的输出很容易解释:您正在调用Date.toString()
始终使用时间格式化1>系统本地时区。 Calendar
对象中的时区无关紧要。
所以看起来你的Calendar
可能是UTC格式,在这种情况下,的日期是 15。
请注意,日志的第一行显然是无意义的:
UTC time: Fri Nov 15 00:28:44 EST 2013
它是UTC还是它的EST。它不可能都是。
目前还不清楚您的数据来自哪里或者您是如何处理它的,但如果您手动通过添加或减少部分来调整日期/时间,那么您几乎可以肯定做错了。理解一个java.util.Date
没有任何时区概念作为其数据的一部分非常重要 - 它只是的瞬间。
要在特定时区格式 Date
,您通常会使用SimpleDateFormat
并在其上指定时区。例如:
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("The time in New York is " + format.format(new Date()));
编辑:现在我们已经看到了你的代码,你绝对应该不做那样的事情。您正在调整时间点,这不是您想要的 - 您只想在同一时间点更改视图,这可以通过Calendar.setTimeZone
更改来实现Calendar.get
返回的内容,并使用DateFormat.setTimeZone
更改用于解析/格式化文本的时区。
答案 1 :(得分:1)
如果我理解你的问题,你可以用这样的东西来做 -
Calendar c = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z YYYY");
formatter.setTimeZone(TimeZone.getTimeZone("UTC")); // <-- Set the timezone on the
// DateFormat
/* Your input date/time */
c.setTime(new GregorianCalendar(2013, 10, 15, 0, 28, 44).getTime());
System.out.println(formatter.format(c.getTime()));
c.setTimeZone(TimeZone.getTimeZone("EST"));
System.out.println(c.getTime());
此代码的输出是
Fri Nov 15 05:28:44 UTC 2013
Fri Nov 15 00:28:44 EST 2013
答案 2 :(得分:1)
java.util
日期时间 API 及其格式化 API SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*。
使用 java.time
(现代日期时间 API)的解决方案:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.of(2013, 11, 15), LocalTime.of(0, 28, 44),
ZoneId.of("Etc/UTC"));
ZonedDateTime zdtNewYork = zdtUtc.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
// Custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
System.out.println(zdtNewYork.format(dtf));
}
}
输出:
2013-11-14T19:28:44-05:00[America/New_York]
Thu Nov 14 19:28:44 EST 2013
从 Trail: Date Time 了解有关现代 Date-Time API 的更多信息。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。