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

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

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

有一个更好的方法吗?

使用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(); } 

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

 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上使用短信时这是一个非常有用的问题。戴夫的回答是错误的。)

使用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(); 

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

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

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

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

……应该工作正常。 但是 ….

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

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

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

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

你可以使用getOffset(oldTime)来获取时间戳的初始猜测,然后检查getOffset(utcTime)以查看它们是否相同。 它基本上很有趣。

Joda Time 应该使用DateTimeZone.getOffsetFromLocal支持这个,但是在DST转换周围稍微破坏了 (IMO)。

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

 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。

可能这可以帮助你我尝试这种方式。 如果有任何最佳和优化方式将本地时间转换为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; } 

结果如下:(参考:检查转换)

 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