我有一个自本地时代以来的毫秒级时间戳,我想将其转换为自UTC时代以来的毫秒级时间戳。从快速查看文档来看,似乎以下内容应该可以实现:
int offset = TimeZone.getDefault().getRawOffset();
long newTime = oldTime - offset;
有更好的方法吗?
不幸的是,这似乎是最好的方法:
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上处理短信时,解决这个问题非常有用。Dave的答案是错误的。
Calendar
来获取本地纪元时的偏移量,然后将其加到本地纪元时间戳上。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();
}
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个小时)。在1970年1月1日的UTC午夜,启动UTC秒表。5小时后,启动您所在地区的本地秒表。这两个秒表的时间差异由仅仅取决于UTC与1970年1月1日当地午夜时刻的本地时间之间的差异。自那时以来的任何夏令时调整都不会影响这些秒表之间的差异。因此,对于您的当前时间或您正在转换的时间的任何夏令时校正都是无关紧要的。您只需要知道您的本地秒表在1970年1月1日之后晚了多少时间。
正如Chris指出的那样,这就是:getOffset(0L),所以:
int offset = TimeZone.getDefault().getOffset(0L);
long newTime = oldTime - offset;
应该工作得很好。然而……
为了更好地理解这一点,请注意:getOffset()中的“0L”是自UTC时代(它是唯一的真实的时代)以来的毫秒数。因此,您的偏移量变量将在UTC午夜时具有偏移量的秒数(例如,在纽约时间是19:00的12/31/1969时)。如果您的当地时间在本地午夜之前的最后几个小时内切换到/从夏令时,则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午夜之后-offset毫秒的时候的时区偏移量。如果没有发生夏令时更改,则localMidnightOffset将等于offset,那么就完成了。如果出现了某些夏令时更改,那么您可能需要四处寻找...可能要继续执行。
localMidnightOffset = TimeZone.getDefault().getOffset(-localMidnightOffset)
getOffset(oldTime)
,因为夏令时可能在两者之间发生了变化……getOffset(oldTime)
来获取时间戳的初始猜测值,然后检查getOffset(utcTime)
以查看它们是否相同。基本上这很有趣。
Joda Time应该支持使用DateTimeZone.getOffsetFromLocal
,但在夏令时转换期间存在一些问题(依我之见)。getOffset(0L)
。重要的是那时候的时间差,在纪元开始时 - 我希望,夏令时转换没有发生在1月1日。 - Chris LercherString 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
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时间。