7

Given an object of Instant, a time string representing the time at a specific ZoneId, How to construct a ZonedDateTime object with the date part (year, month, day) from the instant at the given ZoneId and the time part from the given time string?

For example:

Given an object of Instant of value 1437404400000 (equivalent to 20-07-2015 15:00 UTC), a time string 21:00, and an object of ZoneId representing Europe/London, I want to construct an object of ZonedDateTime equivalent to 20-07-2015 21:00 Europe/London.

Jonik
  • 80,077
  • 70
  • 264
  • 372
YAM
  • 1,362
  • 2
  • 16
  • 30
  • 1
    How do you want the date to be affected by the time, if at all? – Jon Skeet Jul 23 '15 at 16:51
  • I want to extract the date part from the instant and the time part from the string. The time string represents the time at the specified time zone. – YAM Jul 23 '15 at 16:53
  • 1
    But an instant doesn't *have* a date - it's just a point in time, which would be on different dates depending on the time zone. See my post for two options, basically... – Jon Skeet Jul 23 '15 at 16:57
  • Yes, an instant doesn't have a date. I want to extract the date from it at the specified time zone and add the time from the time string (which is also at the specified time zone). – YAM Jul 23 '15 at 17:07
  • 1
    Right, that isn't clear from the question - see my answer for two alternative interpretations, and their consequences. – Jon Skeet Jul 23 '15 at 17:08
  • Thanks Jon, I've edited the question to make it clearer. – YAM Jul 23 '15 at 17:27
  • 1
    Righto - I've simplified my answer to just the one then. – Jon Skeet Jul 23 '15 at 18:17

3 Answers3

9

You'll want to parse the time string to a LocalTime first, then you can adjust a ZonedDateTime from the Instant with the zone, and then apply the time. For example:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm", Locale.US);
LocalTime time = LocalTime.parse(timeText, formatter);
ZonedDateTime zoned = instant.atZone(zoneId)
                             .with(time);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
8

Create the instant and determine the date in UTC of that instant:

Instant instant = Instant.ofEpochMilli(1437404400000L);
LocalDate date = instant.atZone(ZoneOffset.UTC).toLocalDate();

// or if you want the date in the time zone at that instant:

ZoneId tz = ZoneId.of("Europe/London");
LocalDate date = instant.atZone(tz).toLocalDate();

Parse the time:

LocalTime time = LocalTime.parse("21:00");

Create a ZoneDateTime from the LocalDate and the LocalTime at the desired ZoneId:

ZonedDateTime zdt = ZonedDateTime.of(date, time, tz);

As pointed out by Jon you need to decide which date you want as the date in UTC may be different from the date in the given time zone at that instant.

assylias
  • 321,522
  • 82
  • 660
  • 783
0

In addition to the accepted answer and the one written by assylias, there is another simple way to achieve what you want.

You can use ZonedDateTime#ofInstant to obtain a ZonedDateTime from the Instant and then adjust it to the given time using ZonedDateTime#with.

ZonedDateTime.ofInstant(Instant.ofEpochMilli(1437404400000L), ZoneId.of("Europe/London"))
    .with(LocalTime.parse("21:00", DateTimeFormatter.ofPattern("HH:mm", Locale.ENGLISH)))

Demo

Expanded:

ZoneId zoneId = ZoneId.of("Europe/London");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm", Locale.ENGLISH);

Instant instant = Instant.ofEpochMilli(1437404400000L);
LocalTime time = LocalTime.parse("21:00", formatter);

ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, zoneId).with(time);

Learn about the modern Date-Time API from Trail: Date Time.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110