在Java中将本地时间戳转换为UTC时间戳

时间:2010-04-09 16:59:29

标签: java datetime timezone timestamp

我有一个毫秒 - 自 - 本地 - 纪元时间戳,我想将其转换为自UTC时间戳的毫秒时间戳。从快速浏览文档看起来像这样的东西会起作用:

int offset = TimeZone.getDefault().getRawOffset();
long newTime = oldTime - offset;

有更好的方法吗?

7 个答案:

答案 0 :(得分:9)

可悲的是,这似乎是最好的方法:

public static Date convertLocalTimestamp(long millis)
{
    TimeZone tz = TimeZone.getDefault();
    Calendar c = Calendar.getInstance(tz);
    long localMillis = millis;
    int offset, time;

    c.set(1970, Calendar.JANUARY, 1, 0, 0, 0);

    // Add milliseconds
    while (localMillis > Integer.MAX_VALUE)
    {
        c.add(Calendar.MILLISECOND, Integer.MAX_VALUE);
        localMillis -= Integer.MAX_VALUE;
    }
    c.add(Calendar.MILLISECOND, (int)localMillis);

    // Stupidly, the Calendar will give us the wrong result if we use getTime() directly.
    // Instead, we calculate the offset and do the math ourselves.
    time = c.get(Calendar.MILLISECOND);
    time += c.get(Calendar.SECOND) * 1000;
    time += c.get(Calendar.MINUTE) * 60 * 1000;
    time += c.get(Calendar.HOUR_OF_DAY) * 60 * 60 * 1000;
    offset = tz.getOffset(c.get(Calendar.ERA), c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), c.get(Calendar.DAY_OF_WEEK), time);

    return new Date(millis - offset);
}

(我知道这是发布日期后的几个月,但是在Android上使用短信时这是一个非常有用的问题。戴夫的答案是错误的。)

答案 1 :(得分:7)

使用Calendar获取本地Epoch的偏移量,然后将其添加到local-epoch时间戳。

public static long getLocalToUtcDelta() {
    Calendar local = Calendar.getInstance();
    local.clear();
    local.set(1970, Calendar.JANUARY, 1, 0, 0, 0);
    return local.getTimeInMillis();
}

public static long converLocalTimeToUtcTime(long timeSinceLocalEpoch) {
    return timeSinceLocalEpoch + getLocalToUtcDelta();
}

答案 2 :(得分:3)

使用Joda Time会是这样的:

DateTime dt = new DateTime(year, month, day, hour, minute, 0, 0, DateTimeZone.forID("local");

dt.getMillis();

编辑:对不起,这是正确的版本:

DateTime dt = new DateTime(timestamp, DateTimeZone.forID("local");

dt.getMillis();

答案 3 :(得分:3)

实际上,克里斯·拉尔赫(Chris Lercher)在头上打了一针,但他只是简短地发表了评论,所以我想扩大它。

想象一下两个秒表;一个是UTC是1970年1月1日当地时间的地方,而另一个秒表是你所在地区的当地时间(假设它在纽约,距离UTC后5小时)。在 UTC午夜,1970年1月1日,UTC秒表启动。 5小时后,您的本地秒表启动。这两个秒表时间相差一些,仅由UTC与当地时间<1970年1月1日当地午夜之间的差异确定。从那以后,任何日光节约的恶作剧都与这些秒表之间的差异无关。因此,对于目前时间或您转换的时间的任何DST更正都无关紧要。 您需要的只是您的本地秒表在1970年1月1日开始的时间

正如克里斯指出的那样,这只是:getOffset(0L),所以:

int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;

......应该可以正常工作。 然而 ....

为了帮助您真正掌握这一点,请注意:getOffset()中的“0L”是自UTC纪元(这是唯一的真实纪元)以来的毫秒数。因此,您的偏移量变量将具有午夜UTC时的偏移秒数(即,当它在1969年12月31日19:00在纽约时)。如果当地时间在 local 午夜之前的最后几小时切换到/从夏令时开始,则getOffset(0L)将不正确。你需要知道你的夏令时状态在 local 午夜,而不是UTC的午夜。

如果是这种情况,我会感到惊讶(即,在1970年1月1日的当地午夜和UTC午夜之间改变为DST的任何时区)。然而,只是为了好玩,一个廉价的黑客来帮助防范这种情况将检查偏移在这几个小时内是否发生了变化:

// Offset at UTC midnight
int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;
// Offset at Local midnight
int localMidnightOffset = TimeZone.getDefault().getOffset(-offset);

这里,localMidnightOffset将是1970年UTC午夜之后的时间偏移时间偏移量。如果没有发生DST更改,那么localMidnightOffset将等于偏移量,您就完成了。如果某些DST更改发生,那么你可能不得不四处寻找......可能继续做

localMidnightOffset = TimeZone.getDefault().getOffset(-localMidnightOffset)

直到它停止变化......并希望你不会陷入无休止的循环中。我很想知道是否有人有一个保证融合的解决方案。

有点让你希望世界变得平坦,是吗?

答案 4 :(得分:2)

不,这肯定不起作用 - 它不会考虑DST。您也不能只使用getOffset(oldTime),因为DST可能在两者之间发生了变化......

您可以使用getOffset(oldTime)对时间戳进行初步猜测,然后检查getOffset(utcTime)以查看它们是否相同。它基本上很有趣。

Joda Time 使用DateTimeZone.getOffsetFromLocal 支持此功能,但这是围绕DST转换的slightly broken(IMO)。

所有这一切都取决于你所说的“自本地时代以来的毫秒”。如果确实表示自1970年以来经过的毫秒数,那么您可以找到该日期的偏移量,并且无论如何应用它。通常情况下(IME)“本地”毫秒值并不意味着 - 但它意味着“达到特定日期和时间的毫秒数(例如2010年4月9日,下午18:06),但是一个不同的时区“。换句话说,它可以表示基于DST过渡的模糊或不可能的日期/时间组合。

答案 5 :(得分:0)

static final long localTimeZoneoffset = TimeZone.getDefault().getOffset(0L);
static final long dstOffset = TimeZone.getDefault().getDSTSavings();

long offsetOftime = TimeZone.getDefault().getOffset(time.getTime());
long timeinmilli = 0L; 
if(offsetOftime != localTimeZoneoffset)
   timeinmilli = time.getTime()+localTimeZoneoffset+dstOffset;
else
   timeinmilli = time.getTime()+localTimeZoneoffset;
return new Timestamp(timeinmilli);

这对我来说可以转换为UTC。

答案 6 :(得分:0)

可能这可以帮助你我尝试这种方式。如果有任何最佳和优化的方式将本地时间转换为UTC时间戳,请评论我。

String mDate= "Jul 21,2016 1:23 PM";
String mDateFormat =""MMM d,yyyy h:mm a";

致电: getConvertedTimeToUTC(mDate,mDateFormat);

     public String getConvertedTimeToUTC(String ourDate, String mDateFormat) {
            try {
                SimpleDateFormat fmt = new SimpleDateFormat(mDateFormat);
                fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
                Date value = fmt.parse(ourDate);
                if (value != null)
                    return String.valueOf(value.getTime() / 1000);
                else
                    return null;
            } catch (Exception e) {
                ourDate = "00-00-0000 00:00";
            }
            return ourDate;
        }

结果如下:(Ref : check conversion)

Result 1469107380
GMT: Thu, 21 Jul 2016 13:23:00 GMT
Your time zone: Thursday 21 July 2016 06:53:00 PM IST GMT+5:30