Reputation: 8341
I need to get Instant
time from week number of year. Now I'm using old Calendar
API to calculate time:
int week = 1; // week of year
final Calendar cal = new GregorianCalendar();
cal.set(0, 1, 0, 0, 0, 0); // reset calendar
cal.set(Calendar.YEAR, Year.now().getValue());
cal.set(Calendar.WEEK_OF_YEAR, week);
cal.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
final Instant start = cal.getTime().toInstant();
final Instant end = start.plus(Period.ofWeeks(1));
Is it possible to get Instant
from week of year using new Java time API (java.time
package)?
Upvotes: 3
Views: 1581
Reputation: 86379
WeekFields wf = WeekFields.of(Locale.getDefault());
int week = 1; // week of year
LocalDate startDate = LocalDate.now(ZoneOffset.UTC)
.with(wf.weekOfWeekBasedYear(), week)
.with(wf.dayOfWeek(), 1);
Instant startInstant = startDate.atStartOfDay(ZoneOffset.UTC).toInstant();
LocalDate endDate = startDate.plusWeeks(1);
Instant endInstant = endDate.atStartOfDay(ZoneOffset.UTC).toInstant();
System.out.println("" + startInstant + " - " + endInstant);
My locale uses ISO week numbers. The output here was:
2019-12-29T00:00:00Z - 2020-01-05T00:00:00Z
If you want ISO weeks independently of the locale, set wf
to WeekFields.ISO
. If you want some other week numbering scheme, set wf
accordingly.
In case any other readers were wondering, Kirill is defining the end of the week as the first moment of the following week. This is recommended. It’s known as using half-open intervals for time intervals.
I also agree with the question that one should clearly prefer using java.time for this task rather than Calendar
. Calendar
is poorly designed and long outdated, and I believe that the code using java.time is clearer to read.
Furthermore, the code in the question using Calendar
doesn’t set the day to the first day of the week, so will not give you that day. And while I haven’t tested, I suspect that the code will sometimes produce unexpected results around New Year.
My code using WeekFields
from java.time will stay within the current week-based year, which is not the same as the calendar year. For example, if I had run it on December 30, 2019, it would still have given med week 1 of 2020 because we were already in that week.
Upvotes: 2
Reputation: 2177
In order to set the month you can use this lambda expression:
LocalDate.now().with(temporal
-> temporal.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 1l)
);
Now get instant is easy:
LocalDate localDate = LocalDate.now().with(temporal
-> temporal.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 1l)
);
Instant instant = localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
If you don't want cto change time, then you can use this instead of last line:
Instant instant = localDate.atTime(LocalTime.now()).atZone(ZoneId.systemDefault()).toInstant();
Upvotes: 0
Reputation: 3089
You could adjust the week using the following methods:
LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 0, 0);
System.out.println(localDateTime); //2020-01-01T00:00
localDateTime = localDateTime.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 2);
System.out.println(localDateTime); //2020-01-08T00:00
localDateTime = localDateTime.plusWeeks(10);
System.out.println(localDateTime); //2020-03-18T00:00
and to parse it to Instant depends on what class from the API you are using:
LocalDateTime.now().toInstant(ZoneOffset.of("+04:00"));
ZonedDateTime.now().toInstant();
The LocalDateTime
doest not have a Zone, so you must a provide a ZoneOffset
to parse it to a Instant.
Upvotes: 1