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.
tl;dr
Avoid legacy date-time classes
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 UTCSkip 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.Instant
is not flexibleI suspect your problem was in your attempt to format the value within a
Instant
. TheInstant
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 yourInstant
to adjust into a time zone, rendering aZonedDateTime
object.You seem to want to focus on the time-of-day alone. Extract a
LocalTime
object.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.
Proper time zone
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 asAmerica/Montreal
,Africa/Casablanca
, orPacific/Auckland
. Never use the 2-4 letter abbreviation such asBST
orEST
orIST
as they are not true time zones, not standardized, and not even unique(!).Use smart objects, not dumb strings
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.
Localization
And speaking of localization:
Switch the locale to
Locale.US
for a different kind of result:All the code above was run in Java 13 early-access with the ThreeTen-Backport library per your needs stated in the Question.
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.