日历日期字段未更新

时间:2014-05-12 16:38:45

标签: java date calendar

我正在研究一些处理时区差异的代码(在这种情况下,将日期从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。我只是按原样寻找这个问题的答案。

如果因为日历/日期是糟糕的套餐而无法解决,那很好 - 我只是自己解析日期以获得正确的值。提前谢谢。

3 个答案:

答案 0 :(得分:4)

您没有向我们展示足够的代码来了解正在发生的事情,但您的输出很容易解释:您正在调用Date.toString() 始终使用时间格式化系统本地时区。 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.time

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

ONLINE DEMO

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 desugaringHow to use ThreeTenABP in Android Project