2010-04-09 163 views
15

我有一毫秒,因为本地历元时间戳,我想转换成毫秒,因为-UTC-时代时间戳。从文档快速浏览它看起来像这样的事情会工作:将本地时间戳UTC时间戳在Java中

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

有没有更好的方式来做到这一点?

回答

6

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

这并没有考虑到DST。 – 2010-08-26 06:02:05

+0

@Quartz - 它不必,因为我们正在处理来自Epoch的三角洲。你有一个例子(区域和timeSinceLocalEpoch)哪里失败? – leedm777 2010-09-05 20:25:18

2

没有,那肯定是行不通的 - 它没有考虑DST考虑。你不能只用getOffset(oldTime)无论是作为DST可能在两者之间改变......

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

Joda Time应该支持这种使用DateTimeZone.getOffsetFromLocal但是这slightly broken(IMO)周围DST过渡。

一切真的取决于你所说的“因为当地毫秒为单位”的东西。如果你真的意味着自1970年当地经过毫秒,你可以只发现在该日期的偏移量,并应用不管。通常情况下(IME)“本地”millis值并不完全意味着这个数字 - 它意味着“以毫秒为单位获得特定日期和时间的毫秒数(例如2010年4月9日18:06 pm),但是就一个不同的时区“。换句话说,它可以表示基于DST转换的模糊或不可能的日期/时间组合。

+0

但我认为你可以使用'的getOffset(0L)'所有的事情就是时间差那时候,在时代的开始 - 我希望,1月1日DST转换不会发生。 – 2010-04-09 17:09:53

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上的短信工作Dave的答案是错的)

3

使用约达时间它会是这样:。

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

实际上,克里斯Lercher击中了要害,但他只在很短的评论做到了,所以我想它扩大。

假设有两个秒表;一个是1970年1月1日UTC是当地时间的地方,另一个秒表是本地的(假设它在纽约,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; 

...应该能正常运行。 然而 ....

为了帮助真正掌握这一点,请注意这一点:“01”中的getOffset()是自UTC时代毫秒(这是唯一真正划时代)。因此,您的偏移量变量将在UTC的午夜时间(即,在纽约时间19/19/19/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会是怎样的时区偏移是在一个时间偏移处的毫秒后UTC在1970年的午夜。如果没有发生DST变化,那么localMidnightOffset将等于偏移量,然后就完成了。如果某些DST变化发生,那么你可能不得不四处搜寻...可能继续做一个

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

,直到它停止改变......希望你不要陷入死循环。我很想知道是否有人有保证的融合解决方案。

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

+0

我在SO上看过一段时间的最佳答案 – paz 2013-05-31 17:56:08

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。

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