Instant
is a moment on the timeline in UTC, a count of nanoseconds since the epoch
// Capture the current moment in UTC
Instant.now(); // 2018-11-28T01:51:48.847Z
// Get the epoch
Instant.EPOCH; // 1970-01-01T00:00:00Z
// Reminder: 1000 milliseconds = 1 second
Instant.ofEpochMilli(1000); // 1970-01-01T00:00:01Z
// ZonedDateTime is supported
Instant.from(ZonedDateTime.now()); // 2018-11-29T03:38:33.905Z
// LocalDateTime is not supported
Instant.from(LocalDateTime.now());
// UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
Heads Up! java.time.Instant
is an immutable class an update methods return new instances instead of updating the instance itself.
// I find it interesting that this compiles and runs fine
Instant now = Instant.now();
now = now.plus(1, ChronoUnit.DAYS); // 2019-01-14T16:19:07.939Z
A Duration measures an amount of time using time-based values, i.e. hours, minutes, seconds..
// Creating a Duration: ofNanos, ofSeconds, ofMillis, ofMinutes, ofHours, ofDays
Duration.ofNanos(1); // PT0.000000001S
Duration.ofDays(1); // PT24H
// Using Instant
Duration.between(Instant.EPOCH, Instant.now()); // PT428714H19M29.54S
// Using LocalTime
LocalTime now = LocalTime.now();
// PT1H30M15S
Duration.between(now.minusHours(1).minusMinutes(30).minusSeconds(15), now);
Duration d =
Duration.ofDays(1).plus(Duration.ofHours(12)).plus(Duration.ofMinutes(30));
d.toDays(); // Returns 1, do not expect 1.5!
d.toHours(); // Returns 36! Not 12! Not 36.5!
// Also available: toNanos(), toMillis(), getSeconds(), toMinutes()
Why can’t I get a duration in minutes or hours in java.time?
.. that
get(TemporalUnit)
is essentially a framework-level method - it is not designed for day-today use. Unfortunately the method name get does not imply this, resulting in bugs like callingget(ChronoUnit.MINUTES)
on Duration
// Reminder: a new instance is returned
Duration d = Duration.ofHours(1);
d = d.plusMinutes(30); // PT1H30M
Duration extends TemporalAmount which is used in various places in the API.
// Example with Instant.plus(TemporalAmount)
Duration dayz = Duration.ofDays(20000); // 20000 days
Instant.EPOCH.plus(dayz); // 2024-10-04T00:00:00Z
// Example with LocalTime.plus(TemporalAmount)
LocalTime localTime = LocalTime.of(12, 0);
Duration halfAnHour = Duration.ofMinutes(30);
localTime = localTime.plus(halfAnHour) // 12:30
A Period measures an amount of time using date-based values, i.e. years, months, days..
Why can I not get number of calendar days from a Period
?
.. it is not possible from a Period to deduce the actual number of calendar days in the period. A Period is not tied to specific dates, once constructed in the way you show, it loses track of the actual calendar dates.
For example your first period represents a period of 1 month and 1 day. But the period does not care which month. It is simply a concept of “a month and a day”.
To get number of days between two dates, use
ChronoUnit.DAYS.between(Temporal, Temporal)
..How to calculate the number of days in a period? - StackOverflow
// Period of years, months, days
Period.of(1, 1, 1); // P1Y1M1D
Period.ofDays(45); // P45D
// also available: ofMonths, ofYears
Period.between(LocalDate.now(), LocalDate.now().plusDays(1)); // P1D
// You can only use LocalDates, not LocalDateTimes, not ZonedDateTimes
Does the following code compile? Run without any exceptions? What is the returned instance? (A period of .. ..?)
Period.ofYears(1).ofMonths(1).ofDays(1);
LocalDate.now(); // 2018-11-25
LocalDate.of(1984, 9, 3); // 1984-09-03
LocalDate.parse("1984-09-03"); // 1984-09-03
// There is no direct link between an Instant and a LocalDate
LocalDate ld = LocalDate.of(1984, 9, 3);
ld.getDayOfWeek(); // DayOfWeek.MONDAY
ld.getDayOfMonth(); // 3
ld.getDayOfYear(); // 247
LocalDate ld = LocalDate.of(1984, 9, 3);
ld.getMonth(); // Month.SEPTEMBER
ld.getMonthValue(); // 9
LocalDate ld = LocalDate.of(1984, 9, 3);
ld.lengthOfMonth(); // 30
ld.isLeapYear(); // true
ld.lengthOfYear(); // 366
ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.now().minusDays(1)); // -1L
Heads Up! java.time.LocalDate
is an immutable class an update methods return new instances instead of updating the instance itself.
LocalDate ld = LocalDate.of(1983, 9, 3);
ld.plusYears(1); // 1984-09-03 ➤ This is most likely what you want
ld.plusDays(365); // 1984-09-02 ➤ It is not the 3rd of 84 due to leap year
// Using Period
ld.plus(Period.ofYears(1)); // 1984-09-03 ➤ This is what you want
ld.plus(Period.ofDays(365)); // 1984-09-02 ➤ It is not the 3rd due to leap year
// Using withYear
ld.withYear(1984); // 1984-09-03 ➤ This is most likely what you want
// Using plus with ChronoUnit.YEARS
ld.plus(1, ChronoUnit.YEARS); // 1984-09-03 ➤ This is most likely what you want
// Trying to update a LocalDate with a Duration will throw a Runtime Exception
LocalDate.now().plus(Duration.ofDays(1));
// UnsupportedTemporalTypeException: Unsupported unit: Seconds
LocalDate.now().equals(LocalDate.now()); // true
LocalDate.now().isEqual(LocalDate.now()); // true
LocalTime.of(22, 30); // 22:30
LocalTime.of(22, 30, 45); // 22:30:45
LocalTime.parse("22:30"); // 22:30
LocalTime.now(); // 22:57:36.162
LocalDateTime.now();
LocalDateTime.parse("2019-01-01T00:00:00");
LocalDateTime.parse("2019-01-01 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalDateTime
has no time zone information
ZoneOffset.UTC
Instant now = Instant.now();
LocalDateTime
.ofInstant(now, ZoneOffset.UTC); // 2018-12-23T15:22:27.016
LocalDateTime
.ofInstant(now, ZoneId.of("America/Toronto")); // 2018-12-23T10:22:27.016
LocalDateTime l = LocalDateTime.parse("2019-01-01 00:00:00",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
l.format(DateTimeFormatter.ofPattern("yy/MM/dd HH:mm")); // 19/01/01 00:00
LocalDateTime ldt = LocalDateTime.of(2018, 1, 1, 12, 0, 0);
ldt = ldt.plusDays(1); // 2018-01-02T12:00
ldt = ldt.plusHours(1); // 2018-01-02T13:00
ZonedDateTime.now();
// 2018-11-28T23:30:08.454-05:00[America/Toronto]
ZonedDateTime.now(Clock.systemDefaultZone());
// 2018-11-28T23:30:08.456-05:00[America/Toronto]
ZonedDateTime.now(Clock.systemUTC());
// 2018-11-29T04:30:08.456Z
ZonedDateTime.of(2018, 1, 1, 12, 0, 0, 0, ZoneId.systemDefault());
// 2018-01-01T12:00-05:00[America/Toronto]
// Remember ZonedDateTime.of requires nanoseconds
ZonedDateTime parse = ZonedDateTime.parse("2018-01-01T08:00:00Z");
parse.getZone(); // Z
// Z stands for Zulu Timezone, which is +0 offset from GMT
ZonedDateTime parse = ZonedDateTime.parse("2018-01-01T08:00:00-05:00");
parse.getZone(); // -05:00
// I guess that is a fixed offset and not a real timezone..
ZonedDateTime parse
= ZonedDateTime.parse("2018-01-01T08:00:00-00:00[America/Toronto]");
// 2018-01-01T08:00-05:00[America/Toronto]
parse.getZone(); // America/Toronto
// Note how the offset passed in the String (00:00) is ignored by Java!
LocalDate ld = LocalDate.of(1984, 9, 3);
// Basically attaching time zone information to a particular date
ld.atStartOfDay(ZoneId.of("America/Toronto"));
// 1984-09-03T00:00-04:00[America/Toronto]
ld.atStartOfDay(ZoneId.of("Europe/Istanbul"));
// 1984-09-03T00:00+03:00[Europe/Istanbul]
ZonedDateTime zdt = ZonedDateTime.now();
// 2018-12-23T10:41:45.322-05:00[America/Toronto]
zdt.withZoneSameInstant(ZoneId.of("Europe/Istanbul"));
// 2018-12-23T18:41:45.322+03:00[Europe/Istanbul]
ZonedDateTime zdt = ZonedDateTime.now();
// 2018-12-23T10:41:45.322-05:00[America/Toronto]
zdt.toInstant().atZone(ZoneId.of("Europe/Istanbul"));
// 2018-12-23T10:41:45.322-05:00[America/Toronto]
Duration
to ZonedDateTime
will take any daylight savings
into account
ZoneOffset
changes in the following example// DayLightSavings time for Toronto in 2019: Sunday, March 10, 2:00 am
ZonedDateTime zdt =
ZonedDateTime.of(
LocalDate.of(2019, 3, 10),
LocalTime.of(1, 0),
ZoneId.of("America/Toronto")); // 2019-03-10T01:00-05:00[America/Toronto]
zdt = zdt.plus(Duration.ofHours(1)); // 2019-03-10T03:00-04:00[America/Toronto]
Another example for observing the above behavior
LocalDateTime ldt = LocalDateTime.of(2019, 3, 10, 0, 0, 0);
ZoneId zoneId = ZoneId.of("America/Toronto");
ZonedDateTime.of(ldt, zoneId); // 2019-03-10T00:00-05:00[America/Toronto]
ldt = ldt.plusDays(1);
ZonedDateTime.of(ldt, zoneId); // 2019-03-11T00:00-04:00[America/Toronto]
temporal = temporal.with(temporalAdjuster);
class NextWorkingDay implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate nw = ((LocalDate) temporal).plusDays(1);
while (nw.getDayOfWeek() == DayOfWeek.SATURDAY
|| nw.getDayOfWeek() == DayOfWeek.SUNDAY) {
nw = nw.plusDays(1);
}
return nw;
}
}
class FirstTuesdayOfAMonth implements TemporalAdjuster {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate ld = ((LocalDate) temporal)
.with(TemporalAdjusters.firstDayOfMonth());
while (ld.getDayOfWeek() != DayOfWeek.TUESDAY) {
ld = ld.plusDays(1);
}
return ld;
}
}
LocalDate.now().with(new NextWorkingDay());
LocalDate.now().with(new FirstTuesdayOfAMonth());
Locale
sLocalDateTime ldt = LocalDateTime.now();
ldt.format(DateTimeFormatter.ofPattern("dd/MM/yy")); // 13/02/19
// Uses the system default locale with short format style
LocalDateTime ldt = LocalDateTime.now();
ldt.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT));
// 13/02/19 8:13 PM
// Overrides with a specific Locale
LocalDateTime ldt = LocalDateTime.now();
ldt.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
.withLocale(new Locale("tr"))); // 13.02.2019 20:00
ZonedDateTime ldt = ZonedDateTime.now().withZoneSameInstant(ZoneId.of("Europe/Istanbul"));
ldt.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(new Locale("tr"))) ; // 14 Şubat 2019 Perşembe 04:04:43 EET
// Heads UP! There are also ofLocalizedDate and ofLocalizedTime methods!
Daylight Saving Times
final Set<ZonedDateTime> dayLightSavingZonedDateTimes = new HashSet<>();
ZoneId.getAvailableZoneIds().forEach(zoneId -> {
LocalDateTime dateTime
= LocalDateTime.of(LocalDate.of(2018, 1, 1), LocalTime.of(0, 0, 0));
ZonedDateTime now = ZonedDateTime.of(dateTime, ZoneId.of(zoneId));
while (2018 == now.getYear()) {
int hour = now.getHour();
now = now.plusHours(1);
if (now.getHour() == hour) {
dayLightSavingZonedDateTimes.add(now);
}
}
});
dayLightSavingZonedDateTimes
.stream().limit(5).forEach(time -> System.out.println(time));
// 2018-11-04T01:00-05:00[America/Indiana/Petersburg]
// 2018-11-04T01:00-10:00[US/Aleutian]
// 2018-10-28T02:00+01:00[Europe/Brussels]
// 2018-10-28T03:00+02:00[Europe/Sofia]
// 2018-10-28T02:00+01:00[Europe/Vienna]
Day of the Programmer
// Print the Day of the Programmer (the 256th day of the year) for 2011 and 2012
IntStream.rangeClosed(2011, 2012).forEach(year -> {
LocalDate programmersDay = LocalDate.of(year, 1, 1).plusDays(255);
System.out.println(programmersDay);
});
// 2011-09-13
// 2012-09-12
Number of Days until Next Birthday
LocalDate today = LocalDate.now();
LocalDate nextBirthday = LocalDate.of(1984, 9, 3).withYear(today.getYear());
// If birthday this year passed already
if (ChronoUnit.DAYS.between(today, nextBirthday) <= 0)
nextBirthday = nextBirthday.plusYears(1);
ChronoUnit.DAYS.between(today, nextBirthday); // long
Find the Time Difference Changes Between Toronto and London for 2018
ZoneId london = ZoneId.of("Europe/London");
ZoneId toronto = ZoneId.of("America/Toronto");
LocalDate ld = LocalDate.of(2018, 1, 1);
LocalTime lt = LocalTime.of(0, 0);
LocalDateTime ldt = LocalDateTime.of(ld, lt);
ZonedDateTime ldtLondon = ZonedDateTime.of(ldt, london);
ZonedDateTime ldtToronto = ZonedDateTime.of(ldt, toronto);
long hoursBetween = ChronoUnit.HOURS.between(ldtLondon, ldtToronto);
System.out.println("Time difference: " + hoursBetween);
System.out.println(ldtToronto);
System.out.println(ldtLondon);
System.out.println("");
while (2018 == ldt.getYear()) {
ldt = ldt.plusHours(1);
ldtLondon = ZonedDateTime.of(ldt, london);
ldtToronto = ZonedDateTime.of(ldt, toronto);
long hours = ChronoUnit.HOURS.between(ldtLondon, ldtToronto);
if (hoursBetween != hours) {
println("Time difference change from " + hoursBetween + " to " + hours);
println(ldtToronto);
println(ldtLondon);
println("");
hoursBetween = hours;
}
}
Output
Time difference: 5
2018-01-01T00:00-05:00[America/Toronto]
2018-01-01T00:00Z[Europe/London]
Time difference changed from 5 to 4
2018-03-11T03:00-04:00[America/Toronto]
2018-03-11T03:00Z[Europe/London]
Time difference changed from 4 to 5
2018-03-25T02:00-04:00[America/Toronto]
2018-03-25T02:00+01:00[Europe/London]
Time difference changed from 5 to 4
2018-10-28T02:00-04:00[America/Toronto]
2018-10-28T02:00Z[Europe/London]
Time difference changed from 4 to 5
2018-11-04T02:00-05:00[America/Toronto]
2018-11-04T02:00Z[Europe/London]
Find Next Particular Weekday
LocalDate now = LocalDate.now(); // It is Tuesday
LocalDate with = now.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
System.out.println(ChronoUnit.DAYS.between(now, with)); // 2
Find the Timezone That Stays Longest (or shortest) in DST
TreeMap<Long,String> periodZoneIdTreeMap =
new TreeMap<>(Comparator.reverseOrder());
LocalDateTime janFirst =
LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear());
ZoneId.getAvailableZoneIds().forEach(id -> {
ZonedDateTime zdt = ZonedDateTime.of(janFirst, ZoneId.of(id));
List<LocalDate> timeChanges = new ArrayList<>();
while (zdt.getYear() == janFirst.getYear()) {
if (!zdt.getOffset().equals(zdt.plusHours(1).getOffset())) {
timeChanges.add(zdt.toLocalDate());
}
zdt = zdt.plusHours(1);
if (timeChanges.size() > 1) {
long between = ChronoUnit.DAYS.between(timeChanges.get(0),
timeChanges.get(1));
periodZoneIdTreeMap.put(between, id);
break;
}
}
});
periodZoneIdTreeMap.entrySet().iterator().next(); // 294=Pacific/Fiji
// Most Recent DST Transition
// DST ended on Sun 20-Jan-2019 at 02:00:00 A.M.
// When local clocks were set backward 1 hour
// Next Scheduled DST Transition
// DST will begin on Sun 27-Oct-2019 at 02:00:00 A.M.
// When local clocks are set forward 1 hour