Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Joda time进行时间转换';太早了';_Java_Timezone_Utc_Jodatime - Fatal编程技术网

Java Joda time进行时间转换';太早了';

Java Joda time进行时间转换';太早了';,java,timezone,utc,jodatime,Java,Timezone,Utc,Jodatime,我们有一个时间非常关键的应用程序。我们使用joda进行时间转换,并以UTC时间存储所有数据。我们已经制作了一段时间,一切都很完美,但是 现在我们注意到,在时间更改前几个小时发生的事件已经转换得太早了!事实上,保存到数据库的UTC时间缩短了一小时 这里有一个例子。我的事件发生在2010年11月6日太平洋时间晚上9点,通常会保存为2010年11月7日凌晨4点。然而,由于夏令时在7号结束(大概是凌晨2点),所以这段时间会被转换并存储为2010年7月11日凌晨5点 我们需要在太平洋标准时间凌晨2点,在太

我们有一个时间非常关键的应用程序。我们使用joda进行时间转换,并以UTC时间存储所有数据。我们已经制作了一段时间,一切都很完美,但是

现在我们注意到,在时间更改前几个小时发生的事件已经转换得太早了!事实上,保存到数据库的UTC时间缩短了一小时

这里有一个例子。我的事件发生在2010年11月6日太平洋时间晚上9点,通常会保存为2010年11月7日凌晨4点。然而,由于夏令时在7号结束(大概是凌晨2点),所以这段时间会被转换并存储为2010年7月11日凌晨5点

我们需要在太平洋标准时间凌晨2点,在太平洋标准时间区域内实际发生DST变化之前,不记录DST变化。我认为joda会处理这个问题,特别是因为它被吹捧为比java的默认功能有很大的改进

您的任何反馈都会很有帮助,特别是如果您能在明天的时间改变之前将其发送给我们!在那之后,它将是学术性的,但仍然是一个有用的讨论

下面是我们用来执行时区更改并将结果作为常规java日期对象的一些代码

public Date convertToTimeZone(Date dt, TimeZone from, TimeZone to){
    DateTimeZone tzFrom = DateTimeZone.forTimeZone(from);
    DateTimeZone tzTo = DateTimeZone.forTimeZone(to);

    Date utc = new Date(tzFrom.convertLocalToUTC(dt.getTime(), false));
    Date convertedTime = new Date(tzTo.convertUTCToLocal(utc.getTime()));
    return convertedTime;
}
编辑:下面注释的代码示例

public Date convert(Date dt, TimeZone from, TimeZone to) {
    long fromOffset = from.getOffset(dt.getTime());
    long toOffset = to.getOffset(dt.getTime());

    long convertedTime = dt.getTime() - (fromOffset - toOffset);
    return new Date(convertedTime);
}
完整的单元测试示例

package com.test.time;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Instant;
import org.junit.Before;
import org.junit.Test;

public class TimeTest {
Calendar nov6;
Calendar nov1;
Calendar nov12;

@Before
public void doBefore() {
    // November 1st 2010, 9:00pm (DST is active)
    nov1 = Calendar.getInstance();
    nov1.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
    nov1.set(Calendar.HOUR_OF_DAY, 21);
    nov1.set(Calendar.MINUTE, 0);
    nov1.set(Calendar.SECOND, 0);
    nov1.set(Calendar.YEAR, 2010);
    nov1.set(Calendar.MONTH, 10); // November
    nov1.set(Calendar.DATE, 1);

    // November 6st 2010, 9:00pm (DST is still active until early AM november 7th)
    nov6 = Calendar.getInstance();
    nov6.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
    nov6.set(Calendar.HOUR_OF_DAY, 21);
    nov6.set(Calendar.MINUTE, 0);
    nov6.set(Calendar.SECOND, 0);
    nov6.set(Calendar.YEAR, 2010);
    nov6.set(Calendar.MONTH, 10); // November
    nov6.set(Calendar.DATE, 6);

    // November 12th 2010, 9:00pm (DST has ended)
    nov12 = Calendar.getInstance();
    nov12.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
    nov12.set(Calendar.HOUR_OF_DAY, 21);
    nov12.set(Calendar.MINUTE, 0);
    nov12.set(Calendar.SECOND, 0);
    nov12.set(Calendar.YEAR, 2010);
    nov12.set(Calendar.MONTH, 10); // November
    nov12.set(Calendar.DATE, 12);
}

@Test
public void test1() {
    //      System.out.println("test1");
    timeTestJava(nov1.getTime(), "equivalent", "US/Arizona", "US/Pacific");
    timeTestJodaOld(nov1.getTime(), "equivalent", "US/Arizona", "US/Pacific");
    timeTestJodaNew(nov1.getTime(), "equivalent", "US/Arizona", "US/Pacific");

    timeTestJava(nov6.getTime(), "equivalent", "US/Arizona", "US/Pacific");
    timeTestJodaOld(nov6.getTime(), "equivalent", "US/Arizona", "US/Pacific");
    timeTestJodaNew(nov6.getTime(), "equivalent", "US/Arizona", "US/Pacific");

    timeTestJava(nov12.getTime(), "minus1", "US/Arizona", "US/Pacific");
    timeTestJodaOld(nov12.getTime(), "minus1", "US/Arizona", "US/Pacific");
    timeTestJodaNew(nov12.getTime(), "minus1", "US/Arizona", "US/Pacific");
}

private void timeTestJodaOld(Date startTime, String text, String from, String to) {
    System.out.println("joda_old: " + startTime);
    Date output = convertJodaOld(startTime, TimeZone.getTimeZone(from), TimeZone.getTimeZone(to));
    System.out.println(text + ": " + output + "\n");
}

private void timeTestJodaNew(Date startTime, String text, String from, String to) {
    System.out.println("joda_new: " + startTime);
    Date output = convertJodaNew(startTime, TimeZone.getTimeZone(from), TimeZone.getTimeZone(to));
    System.out.println(text + ": " + output + "\n");
}

private void timeTestJava(Date startTime, String text, String from, String to) {
    System.out.println("java: " + startTime);
    Date output = convertJava(startTime, TimeZone.getTimeZone(from), TimeZone.getTimeZone(to));
    System.out.println(text + ": " + output + "\n");
}

// Initial Joda implementation, works before and after DST change, but not during the period from 2am-7am UTC on the day of the change
public Date convertJodaOld(Date dt, TimeZone from, TimeZone to) {
    DateTimeZone tzFrom = DateTimeZone.forTimeZone(from);
    DateTimeZone tzTo = DateTimeZone.forTimeZone(to);

    Date utc = new Date(tzFrom.convertLocalToUTC(dt.getTime(), false));
    Date convertedTime = new Date(tzTo.convertUTCToLocal(utc.getTime()));
    return convertedTime;
}

// New attempt at joda implementation, doesn't work after DST (winter)
public Date convertJodaNew(Date dt, TimeZone from, TimeZone to) {
    Instant utcInstant = new Instant(dt.getTime());
    DateTime datetime = new DateTime(utcInstant);

    datetime.withZone(DateTimeZone.forID(to.getID()));
    return datetime.toDate();
}

// Java implementation.  Works.
public Date convertJava(Date dt, TimeZone from, TimeZone to) {
    long fromOffset = from.getOffset(dt.getTime());
    long toOffset = to.getOffset(dt.getTime());

    long convertedTime = dt.getTime() - (fromOffset - toOffset);
    return new Date(convertedTime);
}

}您的代码从根本上被破坏了,因为
日期
对象不能在时区之间“转换”——它代表时间上的一个瞬间
getTime()
返回自UTC Unix纪元以来的时间(毫秒)。
Date
不依赖于时区,因此将
Date
实例从一个时区转换为另一个时区的想法毫无意义。这有点像将一个
int
从“基数10”转换为“基数16”——当你考虑用数字而不是基本数字表示时,基数才有意义

您应该使用
LocalDateTime
表示没有固定时区的日期/时间,或者使用
DateTime
表示有特定时区的日期/时间,或者使用
Instant
表示与
java.util.date
相同的概念

一旦你使用了合适的类型,我相信你不会有任何问题

编辑:如果您的实际代码使用的是具有正确时区的
日历
,则无需执行任何操作即可将其转换为UTC。只需调用
calendar.getTime()
,它将为您提供相应的
日期

例如:

    // Display all Date values as UTC for convenience
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

    // November 6st 2010, 9:00pm (DST is still active until
    // early AM november 7th)
    Calendar nov6 = Calendar.getInstance();
    nov6.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
    nov6.set(Calendar.HOUR_OF_DAY, 21);
    nov6.set(Calendar.MINUTE, 0);
    nov6.set(Calendar.SECOND, 0);
    nov6.set(Calendar.YEAR, 2010);
    nov6.set(Calendar.MONTH, 10); // November
    nov6.set(Calendar.DATE, 6);

    // Prints Sun Nov 07 04:00:00 UTC 2010 which is correct
    System.out.println("Local Nov6 = " + nov6.getTime());

基本上,我不清楚,当您谈到试图保存到UTC时,为什么您要尝试从美国/亚利桑那州转换到美国/太平洋…

而不是提供一个单一的方法,您能提供一个简短但完整的程序来演示这个问题吗?我们现在只能使用java.util.Date,因为我们使用hibernate来持久化数据。我的理解是,joda正在对日期应用偏移量,即使date对象实际上并不知道时区。如果代码从根本上被破坏了,它不是一直被破坏,而不是一年中只有14个小时吗?@samspot:不是日期对象没有真正意识到时区,而是日期总是代表一个瞬间。在时区之间“转换”日期毫无意义。至于为什么它没有一直坏掉——一个简短但完整的例子在这里会很有帮助。仅仅因为你必须在某个时候使用
Date
,并不意味着你必须在任何地方都使用它,是吗?嘿,Jon,我附加了一个非joda的示例,效果非常好。这就是我认为乔达一开始为我所做的。你是说我需要使用joda的其他方面来实现这一点吗?@samspot:是的,你应该使用正确的类型<代码>日期
不是表示“本地”日期/时间的正确类型。非Joda示例可能只能正常工作,因为Java时区数据库太旧,无法了解最近的时区更改。(也许)再一次,通过一个简短但完整的例子,我们可以找出Joda Time为什么会这样做——这也可能说明你是如何因为使用了错误的类型而陷入麻烦的。@Jon我已经发布了一个完整的程序。请参阅convertJodaNew(),了解我根据对话和此链接进行转换的尝试。请注意,这也不起作用。我们在亚利桑那州运行的服务器没有观察到DST,所以我们应该看到DST处于活动状态时时间保持不变,然后DST处于非活动状态时时间比pacific早一个小时。