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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2609360/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:50:55  来源:igfitidea点击:

Converting local timestamp to UTC timestamp in Java

javadatetimetimezonetimestamp

提问by Jeremy Logan

I have a milliseconds-since-local-epoch timestamp that I'd like to convert into a milliseconds-since-UTC-epoch timestamp. From a quick glance through the docs it looks like something like this would work:

我有一个毫秒以来的本地时代时间戳,我想将其转换为毫秒以来的 UTC 时代时间戳。快速浏览一下文档,它看起来像这样可以工作:

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

Is there a better way to do this?

有一个更好的方法吗?

采纳答案by leedm777

Use a Calendarto get what the offset was at the local Epoch, then add that to the local-epoch timestamp.

使用 aCalendar获取本地纪元的偏移量,然后将其添加到本地纪元时间戳。

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

回答by Jon Skeet

No, that definitely won't work - it doesn't take DST into account. You can't just use getOffset(oldTime)either, as the DST may have changed between the two...

不,这绝对行不通——它不考虑夏令时。您不能只使用getOffset(oldTime)两者之一,因为 DST 可能在两者之间发生了变化......

You could use getOffset(oldTime)to get an initial guess at the timestamp, then check getOffset(utcTime)to see whether they're the same or not. It gets fun, basically.

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

Joda Timeshouldsupport this using DateTimeZone.getOffsetFromLocalbut that's slightly broken(IMO) around DST transitions.

Joda Time应该支持这种使用,DateTimeZone.getOffsetFromLocal但在 DST 转换周围有点损坏(IMO)。

All of this really depends on what you mean by "milliseconds since local epoch". If you reallymean elapsed milliseconds since local 1970, you could just find out the offset at that date, and apply that regardless. Typically (IME) a "local" millis value doesn't mean quite that though - it means "the number of millis to get to a particular date and time (e.g. April 9th 2010, 18:06pm) in UTC, but in respect of a different time zone". In other words, it can represent ambiguous or impossible date/time combinations based on DST transitions.

所有这些实际上取决于您所说的“自本地纪元以来的毫秒数”是什么意思。如果你真的意味着自1970年当地经过毫秒,你可以只发现在该日期的偏移量,并应用不管。通常(IME)“本地”毫秒值并不完全意味着 - 它意味着“在UTC中到达特定日期和时间(例如2010年4月9日,下午18:06)的毫秒数,但关于不同的时区”。换句话说,它可以表示基于 DST 转换的模糊或不可能的日期/时间组合。

回答by Ross Light

Sadly, this seems to be the best way to do this:

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

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);
}

(I know that this is several months past post date, but it's a problem that is very useful to solve when working with text messages on Android. dave's answer is wrong.)

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

回答by lisak

Using Joda Time it would be like this :

使用 Joda Time 是这样的:

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

dt.getMillis();

EDITED: Sorry, this is the correct version :

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

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

dt.getMillis();

回答by Jemenake

Actually, Chris Lercher hit the nail on the head, but he only made it in a short comment, so I wanted to expand on it.

实际上,Chris Lercher 一针见血,但他只是在简短的评论中说到了,所以我想扩展一下。

Imagine two stopwatches; one is somewhere where UTC is the local time on Jan 1, 1970, and the other stopwatch is local to your area (let's say that it's in New York, 5 hours after UTC). At UTC midnight, on Jan 1, 1970, the UTC stopwatch is started. 5 hours later, your local stopwatch is started. Those two stopwatch times differ by some amount, determined only by what the difference between UTC was from your local time at local midnighton Jan 1, 1970. Any daylight-saving shenanigans, since then, have no bearing on the difference between those stopwatches. So, any DST corrections for your presenttime or for the times you're converting, are irrelevant. All you need is how much later your local stopwatch started on Jan 1, 1970.

想象两个秒表;一个是 UTC 是 1970 年 1 月 1 日当地时间的某个地方,另一个秒表是您所在地区的本地时间(假设它在纽约,UTC 后 5 小时)。在UTC 午夜,即 1970 年 1 月 1 日,UTC 秒表启动。5 小时后,您的本地秒表启动。这两个秒表时间存在一定差异,仅取决于 UTC 与您在1970 年 1 月 1 日当地午夜的当地时间之间的差异。从那时起,任何夏令时的恶作剧都与这些秒表之间的差异无关。因此,任何针对您当前时间或您正在转换的时间的DST 更正都是无关紧要的。您所需要的只是本地秒表在 1970 年 1 月 1 日开始运行的时间

As Chris pointed out, this is just: getOffset(0L), so:

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

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

... should work fine. However....

...应该可以正常工作。不过……

To help really grasp this, note this: that "0L" in getOffset() is the milliseconds since the UTC epoch (which is the only realepoch). So, your offset variable is going to have the number of seconds of offset at midnight UTC (ie, when it was, say, 19:00 on 12/31/1969 in New York). If your local time switched to/from daylight-saving in those last hours before localmidnight, then getOffset(0L) wouldn't be correct. You need to know what your daylight-saving status was at localmidnight, not UTC's midnight.

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

I'd be surprised if this were the case, anywhere (ie, any timezone which changed to/from DST between their local midnight and UTC midnight of Jan 1, 1970). However, just for fun, a cheap hack to help guard against this would be to check if the offset changed in those hours:

如果在任何地方都是这种情况,我会感到惊讶(即,在本地午夜和 1970 年 1 月 1 日的 UTC 午夜之间更改为/从 DST 更改的任何时区)。然而,只是为了好玩,一个廉价的 hack 来帮助防止这种情况是检查偏移量在那些小时内是否发生了变化:

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

Here, localMidnightOffset will be what the timezone offset was at a time -offset milliseconds after UTC midnight in 1970. If no DST change happened, then localMidnightOffset will equal offset, and you're done. If some DST change didoccur, then you might have to hunt around... probably keep doing a

在这里,localMidnightOffset 将是 1970 年 UTC 午夜之后的 time-offset 毫秒时的时区偏移量。如果没有发生 DST 更改,则 localMidnightOffset 将等于偏移量,您就完成了。如果确实发生了一些 DST 更改,那么您可能需要四处寻找……可能会继续做

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

until it stops changing... and hope you don't get caught in an endless loop. I'm curious to see if anybody has a guaranteed-converging solution.

直到它停止改变……希望你不要陷入无限循环。我很想知道是否有人有保证收敛的解决方案。

Kinda makes you wish the world were flat, huh?

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

回答by Wilson

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);

This worked for me to convert to UTC.

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

回答by Chintan Khetiya

May be this can help you i have try this way. Please comment me if there is any best and optimize way to convert local time to UTC timestamp.

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

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

Call :getConvertedTimeToUTC(mDate,mDateFormat);

称呼 :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;
        }

Here is the result : (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