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
精彩评论