I have the following code:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.UK);
Instant inst = DateTimeUtils.toInstant(sdf.parse("2019-08-13T18:00:00Z"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm").withLocale(Locale.UK).withZone(ZoneId.of("Europe/London"));
System.out.println(formatter.format(inst));
//prints 18:00
This is surprising to me as I thought inst
would be a GMT/UTC time and the formatter
would format it to London time (which is BST (UTC+1:00) for this date), producing 19:00
.
What am I missing here?
I'm guessing this is a generic issue with my code, but if it makes a difference this is using the org.threeten.bp.*
classes from the ThreeTen-Backport project, further adapted for early Android in the ThreeTenABP project.
Instant // Represent a moment in UTC.
.parse( // Generate a `Instant` object from the content of text input.
"2019-08-13T18:00:00Z" // String in standard ISO 8601 format.
) // Returns a `Instant` object.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "Europe/London" ) // Specify a time zone using name in proper `Continent/Region` format. Never use 2-4 letter pseudo-zones such as `BST`.
) // Returns a `ZonedDateTime` object.
.toLocalTime() // Extract the time-of-day, without a date and without a time zone or offset. Returns a `LocalTime` object.
.format( // Generate text representing the content of this `LocalTime` object.
DateTimeFormatter
.ofLocalizedTime ( FormatStyle.SHORT ) // Automatically localize while generating a `String`.
.withLocale ( Locale.UK ) // Locale determines the human language and cultural norms to use in localizing.
) // Returns a `String` object.
19:00
Your are mixing the terrible legacy classes ( SimpleDateFormat
, Date
) with the modern java.time classes. Don't do that. Use only java.time .
Instant
= moment in UTC Skip your first two lines of code. Your input string "2019-08-13T18:00:00Z"
is in standard ISO 8601 format. These standard formats are used by default by the java.time classes when parsing/generating strings. So no need to specify a formatting pattern.
String input = "2019-08-13T18:00:00Z" ;
Instant instant = Instant.parse( input ) ;
instant.toString(): 2019-08-13T18:00:00Z
Instant
is not flexible I suspect your problem was in your attempt to format the value within a Instant
. The Instant
class is a basic building-block class within java.time . It merely represents a moment in UTC. It is not intended for things such as flexible generation of strings.
The more flexible classes are OffsetDateTime
& ZonedDateTime
classes.
ZonedDateTime
Apply a ZoneId
to your Instant
to adjust into a time zone, rendering a ZonedDateTime
object.
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2019-08-13T19:00+01:00[Europe/London]
You seem to want to focus on the time-of-day alone. Extract a LocalTime
object.
LocalTime lt = zdt.toLocalTime ();
lt.toString(): 19:00
For the London region in Daylight Saving Time (DST) on that date, the offset-from-UTC is one hour ahead. So we see the time-of-day is 7 PM versus the 6 PM of UTC.
By the way BST
is not a time zone. I suggest you avoid using these pseudo-zones.
Specify a proper time zone name in the format of Continent/Region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 2-4 letter abbreviation such as BST
or EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
Your example code suggests you are too focused on strings. Use smart objects, not dumb strings.
Get your objects straight, using appropriate types. Generating strings should be the last step, a side-effort, akin to localization. Your business logic should be done by using proper objects, not by manipulating strings.
And speaking of localization:
Locale locale = Locale.UK;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedTime ( FormatStyle.MEDIUM ).withLocale ( locale );
String output = lt.format ( f );
19:00:00
Switch the locale to Locale.US
for a different kind of result:
7:00:00 PM
All the code above was run in Java 13 early-access with the ThreeTen-Backport library per your needs stated in the Question.
import org.threeten.bp.* ;
import org.threeten.bp.format.* ;
Note to the reader: The ThreeTen-Backport library is further adapted for early Android in the ThreeTenABP library. See How to use ThreeTenABP in Android . If using Android 26 and later, the java.time classes are bundled, so you do not need the back-port at all.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.