Converting local timestamp to UTC timestamp in Jav

2019-01-18 03:30发布

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:

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

Is there a better way to do this?

7条回答
家丑人穷心不美
2楼-- · 2019-01-18 04:14

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

查看更多
何必那么认真
3楼-- · 2019-01-18 04:15
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.

查看更多
看我几分像从前
4楼-- · 2019-01-18 04:19

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.

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 midnight on Jan 1, 1970. Any daylight-saving shenanigans, since then, have no bearing on the difference between those stopwatches. So, any DST corrections for your present time or for the times you're converting, are irrelevant. All you need is how much later your local stopwatch started on Jan 1, 1970.

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

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 real epoch). 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 local midnight, then getOffset(0L) wouldn't be correct. You need to know what your daylight-saving status was at local midnight, not UTC's midnight.

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:

// 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 did occur, then you might have to hunt around... probably keep doing a

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?

查看更多
贼婆χ
5楼-- · 2019-01-18 04:20

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

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();
}
查看更多
Juvenile、少年°
6楼-- · 2019-01-18 04:22

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.

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

Call : 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
查看更多
一纸荒年 Trace。
7楼-- · 2019-01-18 04:27

Using Joda Time it would be like this :

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();
查看更多
登录 后发表回答