开发者

Java timezone conversion

I have a String, representing time in UTC. I need to convert it to long representing milliseconds since midnight at EST, considering daylight saving times. For example, in January, the offset is 5 hours, but in June 4 hours.

However, the code below displays the same offset of 5 hours for both June and January. The variable tzOffset = -18000000 (=-5 hours), regardless the date month.

Please advise,

Thanks!

package TimeConversion;

import java.text.SimpleDateFormat;

import java.util.*;

public class TimeConversion {

    public static void main(String[] args) throws Exception {

        String utcTime = "20100101120000000";
        Simpl开发者_运维问答eDateFormat sdfIn = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        sdfIn.setTimeZone(TimeZone.getTimeZone("UTC"));        
        long utcMillis = sdfIn.parse(utcTime).getTime();
        long tzOffset = TimeZone.getTimeZone("EST").getOffset(utcMillis);
        long estMillis = utcMillis + tzOffset;
        long estMillisSinceMidnight = estMillis % 86400000;
        System.out.println("utcTime = " + utcTime + "\nestMillisSinceMidnight = " + estMillisSinceMidnight + "(" + 24.0 * estMillisSinceMidnight / 86.4e6 + ")");
    }

}


You could steal some code from this calendar conversion utility. What you probably need is getLocalTime. Disclaimer: I wrote it.


tl;dr

Duration                                                     // Represent a span-of-time not attached to the timeline, on a scale of hours-minutes-seconds.
.between(                                                    // Instantiate a `Duration` by calculating time elapsed between a pair of moments.
    LocalDateTime.parse(                                     // Represent a date with time-of-day but lacking the context of a time zone or offset-from-UTC.
        "20100101120000000" ,                                // Tip: Use standard ISO 8601 formats instead of inventing your own.
        DateTimeFormatter.ofPattern( "uuuuMMddHHmmssSSS" ) 
    )                                                        // Returns a `LocalDateTime` object.
    .atZone(                                                 // Place this date-with-time in the context of a particular time zone to determine a moment, a specific point on the timeline.
        ZoneId.of( "America/Montreal" )                      // Never use 2-4 character pseudo-zones such as `EST` or `EDT`. Real time zone names are in `Continent/Region` format.
    )                                                        // Returns a `ZonedDateTime` object.
    .toLocalDate()                                           // Extracts the date-only portion from a `ZonedDateTime` object.
    .atStartOfDay(                                           // Determine the first moment of the day on that date as seen in a particular time zone.
        ZoneId.of( "America/Montreal" )
    )                                                        // Returns a `ZonedDateTime` object, rather than altering original. (immutable objects)                     
    ,
    LocalDateTime.parse( 
        "20100101120000000" , 
        DateTimeFormatter.ofPattern( "uuuuMMddHHmmssSSS" ) 
    )
    .atZone(
        ZoneId.of( "America/Montreal" )
    )
)                                                             // Returns a `Duration`.
.toMillis()                                                   // Returs a `long` integer. 

Beware of possible data loss as any microseconds or nanoseconds are not accounted for with a coarser count of milliseconds.

ISO 8601

String utcTime = "20100101120000000";

By the way, rather than invent your own formats, use the standard ISO 8601 formats for exchanging date-time values as text. The standard was invented for that very purpose.

java.time

Define a formatting pattern to match your input.

String input = "20100101120000000";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmmssSSS" ) ;

Parse as a LocalDateTime object, because your input lacks the context of a time zone or offset-from-UTC.

LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

If you know for certain the intended time zone for that date and time-of-day, apply a ZoneId to get a ZonedDateTime.

I am guessing by EDT you mean east coast time somewhere North America or the Caribbean. That could be any number of various time zones such as America/New_York, America/Louisville, and so on. I arbitrarily guessed America/Montreal for my code example here.

Never use the 2-4 letter abbreviation such as EDT or EST or IST as they are not true time zones, not standardized, and not even unique(!). Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;

You want to get elapsed time since the first moment of the day as seen in that time zone, until this ZonedDateTime object we just determined.

Let java.time determine the first moment of the day. In some zones on some dates, the day may not start at 00:00.

LocalDate ld = zdt.toLocalDate() ;
ZonedDateTime zdtStartOfDay = ld.atStartOfDay( z ) ;

Calculate elapsed time as a Duration. Feed inputs as Instant objects, which represent the same moment as our ZonedDateTime objects but are adjusted to UTC (an offset of zero hours-minutes-seconds).

Duration d = Duration.between(
    zdtStartOfDay.toInstant() ,
    zdt.toInstant() 
);

Apparently you want to represent that span-of-time as a count of milliseconds. Beware of possible data-loss, as the ZonedDateTime & Instant classes resolve to the finer nanoseconds.

long millis = d.toMillis() ;  // Report entire span-of-time as a count of milliseconds. Beware: possible data loss as any microseconds and nanoseconds are ignored. 

See this code run live at IdeOne.com. We get a result of 12 hours.

d.toString(): PT12H

millis: 43200000

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜