如何获得一个月中特定周的第一天和最后一天
How to get first and last day in specific week in month
我需要帮助 return 给定周的第一天(和最后一天),仅传递该月的第几周以及相应的月份和年份。
我已经在寻找使用 LocalDate 或 Calendar return 的方法,但没有找到。
我的语言环境是 PT-BR - 一周的第一天是星期日
提前致谢。
例如:
Year 2021 - Month 7 (July) - Week 1 - First day: 1 - Last Day: 3
Year 2021 - Month 7 (July) - Week 2 - First day: 4 - Last Day: 10
Year 2021 - Month 7 (July) - Week 3 - First day: 11 - Last Day: 17
Year 2021 - Month 7 (July) - Week 4 - First day: 18 - Last Day: 24
Year 2021 - Month 7 (July) - Week 5 - First day: 25 - Last Day: 31
我发现你的周历方法很有趣,想出了一个接收两个参数(月和年)并建立那个月的周历的方法:
private static Map<Integer, Integer[]> getWeekCalendar(int month, int year) {
Map<Integer, Integer[]> weekCalendar = new HashMap<>();
LocalDate date = LocalDate.of(year,month,1);
int week = 1;
LocalDate firstOfWeek = LocalDate.from(date);
while (date.getMonth().equals(Month.of(month))) {
//if it is a saturday, advance to the next week and register current week bounds
if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
weekCalendar.put(week++, new Integer[]{firstOfWeek.getDayOfMonth(), date.getDayOfMonth()});
firstOfWeek = LocalDate.from(date.plusDays(1L));
}
date = date.plusDays(1L);
}
//this one is necessary because the month may end on a Saturday
if (firstOfWeek.getMonth().equals(Month.of(month))) {
weekCalendar.put(week, new Integer[]{firstOfWeek.getDayOfMonth(), date.minusDays(1L).getDayOfMonth()});
}
return weekCalendar;
}
还有一个主要的 class 用于测试目的:
public static void main(String[] args) {
int wantedMonth = 7;
int wantedYear = 2021;
Map<Integer, Integer[]> weekCalendar = getWeekCalendar(wantedMonth, wantedYear);
weekCalendar.entrySet().stream()
.map(e -> String.format("Year %d - Month %d (%s) - Week %d - First day: %d - Last day: %d", wantedYear, wantedMonth, Month.of(wantedMonth).name(), e.getKey(), e.getValue()[0], e.getValue()[1]))
.forEach(System.out::println);
}
输出:
Year 2021 - Month 7 (JULY) - Week 1 - First day: 1 - Last day: 3
Year 2021 - Month 7 (JULY) - Week 2 - First day: 4 - Last day: 10
Year 2021 - Month 7 (JULY) - Week 3 - First day: 11 - Last day: 17
Year 2021 - Month 7 (JULY) - Week 4 - First day: 18 - Last day: 24
Year 2021 - Month 7 (JULY) - Week 5 - First day: 25 - Last day: 31
没有一个函数可以获取一个月中的第几周。
我整理了一个方法来计算一个月中的第几周。这是我的多次测试之一的测试结果。
Week 1 of July 2021 is 1 - 3
Week 2 of July 2021 is 4 - 10
Week 3 of July 2021 is 11 - 17
Week 4 of July 2021 is 18 - 24
Week 5 of July 2021 is 25 - 31
Week 6 of July 2021 is 0 - 0
Week 1 of August 2021 is 1 - 7
Week 2 of August 2021 is 8 - 14
我根据年份和月份创建了一个LocalDate
。我做了一些日期运算,得到一个月中的星期日和星期六。
这是代码。我测试了 2021 年 7 月和 8 月。它可能适用于其他月份。
import java.time.LocalDate;
public class DatesFinder {
public static void main(String[] args) {
DatesFinder df = new DatesFinder();
int[] days = df.findDays(2021, 7, 1);
System.out.println("Week 1 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 2);
System.out.println("Week 2 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 3);
System.out.println("Week 3 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 4);
System.out.println("Week 4 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 5);
System.out.println("Week 5 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 6);
System.out.println("Week 6 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 8, 1);
System.out.println("Week 1 of August 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 8, 2);
System.out.println("Week 2 of August 2021 is " + days[0] + " - " + days[1]);
}
public int[] findDays(int year, int month, int weekNumber) {
LocalDate date = LocalDate.of(year, month, 1);
int weekday = date.getDayOfWeek().getValue();
// weekday is 1 - Monday to 7 - Sunday.
// convert to 0 - Sunday.
weekday = weekday % 7;
LocalDate sundayDate = date.minusDays(weekday);
int dayIncrement = (weekNumber - 1) * 7;
if (dayIncrement > 0) {
sundayDate = sundayDate.plusDays(dayIncrement);
}
int lowDay = sundayDate.getDayOfMonth();
LocalDate saturdayDate = sundayDate.plusDays(6L);
int highDay = saturdayDate.getDayOfMonth();
// System.out.println(date + " " + sundayDate + " " + lowDay + " " + highDay);
// Test for beginning of month
if (sundayDate.getMonth().compareTo(date.getMonth()) < 0) {
lowDay = 1;
}
// Test for end of month
if (saturdayDate.getMonth().compareTo(date.getMonth()) > 0) {
LocalDate nextMonth = date.plusMonths(1L);
nextMonth = nextMonth.minusDays(1L);
highDay = nextMonth.getDayOfMonth();
}
// Test for outside of month (weekNumber too high)
if (sundayDate.getMonth().compareTo(date.getMonth()) > 0) {
lowDay = 0;
highDay = 0;
}
int[] output = new int[2];
output[0] = lowDay;
output[1] = highDay;
return output;
}
}
java.time
java.util
日期时间 API 及其格式 API、SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*.
解决方案使用 java.time
,现代日期时间 API:
- 使用
WeekFields.of(locale).getFirstDayOfWeek()
查找一周的第一天。
- 使用
TemporalAdjusters.nextOrSame(firstDayOfWeek)
查找一周的最后一天。
- 使用
TemporalAdjusters.lastDayOfMonth()
查找该月的最后一天。
演示:
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.TextStyle;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getWeeks(2021, 7, new Locale("pt", "BR")));
System.out.println("---------------------------------------------------------");
System.out.println(getWeeks(2021, 2, new Locale("pt", "BR")));
System.out.println("---------------------------------------------------------");
System.out.println(getWeeks(2021, 7, new Locale("en", "GB")));
System.out.println("---------------------------------------------------------");
System.out.println(getWeeks(2021, 2, new Locale("en", "GB")));
}
static String getWeeks(int year, int month, Locale locale) {
DayOfWeek firstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek();
LocalDate firstDateOfMonth = LocalDate.of(year, month, 1);
String monthName = Month.of(month).getDisplayName(TextStyle.FULL, Locale.ENGLISH);
int lastDayOfMonth = firstDateOfMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
int firstDay = 1;
int lastDayOfFirstWeek = LocalDate.of(year, month, 1).with(TemporalAdjusters.nextOrSame(firstDayOfWeek))
.getDayOfMonth();
int lastDay = lastDayOfFirstWeek == 1 ? 7 : lastDayOfFirstWeek - 1;
int i;
StringBuilder sb = new StringBuilder();
for (i = 1; i <= lastDayOfMonth / 7; i++) {
sb.append(String.format("Year %d - Month %d (%s) - Week %d - First day: %d - Last Day: %d%n", year, month,
monthName, i, firstDay, lastDay));
firstDay = lastDay + 1;
lastDay += 7;
}
if (lastDayOfFirstWeek != 1 && lastDayOfMonth >= 28)
sb.append(String.format("Year %d - Month %d (%s) - Week %d - First day: %d - Last Day: %d%n", year, month,
monthName, i, firstDay, lastDayOfMonth));
return sb.toString();
}
}
输出:
Year 2021 - Month 7 (July) - Week 1 - First day: 1 - Last Day: 3
Year 2021 - Month 7 (July) - Week 2 - First day: 4 - Last Day: 10
Year 2021 - Month 7 (July) - Week 3 - First day: 11 - Last Day: 17
Year 2021 - Month 7 (July) - Week 4 - First day: 18 - Last Day: 24
Year 2021 - Month 7 (July) - Week 5 - First day: 25 - Last Day: 31
---------------------------------------------------------
Year 2021 - Month 2 (February) - Week 1 - First day: 1 - Last Day: 6
Year 2021 - Month 2 (February) - Week 2 - First day: 7 - Last Day: 13
Year 2021 - Month 2 (February) - Week 3 - First day: 14 - Last Day: 20
Year 2021 - Month 2 (February) - Week 4 - First day: 21 - Last Day: 27
Year 2021 - Month 2 (February) - Week 5 - First day: 28 - Last Day: 28
---------------------------------------------------------
Year 2021 - Month 7 (July) - Week 1 - First day: 1 - Last Day: 4
Year 2021 - Month 7 (July) - Week 2 - First day: 5 - Last Day: 11
Year 2021 - Month 7 (July) - Week 3 - First day: 12 - Last Day: 18
Year 2021 - Month 7 (July) - Week 4 - First day: 19 - Last Day: 25
Year 2021 - Month 7 (July) - Week 5 - First day: 26 - Last Day: 31
---------------------------------------------------------
Year 2021 - Month 2 (February) - Week 1 - First day: 1 - Last Day: 7
Year 2021 - Month 2 (February) - Week 2 - First day: 8 - Last Day: 14
Year 2021 - Month 2 (February) - Week 3 - First day: 15 - Last Day: 21
Year 2021 - Month 2 (February) - Week 4 - First day: 22 - Last Day: 28
从 Trail: Date Time 中了解有关 modern Date-Time API* 的更多信息.
* 无论出于何种原因,如果您必须坚持Java 6 或Java 7,您可以使用ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and 。
年历周数
为了扩展 ,让我们获取一年的周历。对于我们这一周,让我们使用第三方 class 来表示几天的时间跨度。我们收集月地图作为键,周列表作为值。从该地图我们可以检索任何特定的一周。
ThreeTen-Extra 图书馆,LocalDateRange
class
将 ThreeTen-Extra 库添加到您的项目中。这给了我们 LocalDateRange
class 将时间跨度表示为一对 LocalDate
对象。这个class提供了abuts
、contains
等很多方便的方法,在你处理周的时候可能会有帮助。
指定 Year
和 Locale
。我们根据区域设置确定一周中的第一天,如 .
所示
每月循环,然后每周循环
我们使用 Month
objects returned by the Month.values
method on this enum. We combine each month with the year to get a YearMonth
对象数组循环一年中的每个月。
对于每个 YearMonth
,我们得到该月的第一天。然后我们及时回溯得到一周的第一天 (DayOfWeek
), or use the same date if it is indeed our desired day-of-week. A TemporalAdjuster
moves us along the timeline. You can write your own TemporalAdjuster
implementation, but we can find one already written for our needs here: TemporalAdjusters.previousOrSame( DayOfWeek )
.
然后我们循环计算每月的每一周,从一对 LocalDate
对象中创建一个 LocalDateRange
作为每周的开始和结束。我们将那些 LocalDateRange
个对象收集到 NavigableSet
, a TreeSet
.
我们通过将每个 YearMonth
作为键添加到 NavigableMap
(TreeMap
) 来报告我们的结果,其值为 LocalDateRange
的 NavigableSet
。
示例代码
package work.basil.datetime;
import org.threeten.extra.LocalDateRange;
import java.time.*;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;
public final class WeeklyCalendar {
public static final NavigableMap < YearMonth, List < LocalDateRange > > calculate ( final Year year , final Locale locale ) {
Objects.requireNonNull( year );
DayOfWeek startOfWeek = WeekFields.of( Objects.requireNonNull( locale ) ).getFirstDayOfWeek();
NavigableMap < YearMonth, List < LocalDateRange > > navMap = new TreeMap <>();
TemporalAdjuster adjuster = TemporalAdjusters.previousOrSame( startOfWeek );
for ( Month month : Month.values() ) {
List < LocalDateRange > weeks = new ArrayList <>();
YearMonth yearMonth = year.atMonth( month );
LocalDate start = yearMonth.atDay( 1 ).with( adjuster );
LocalDate end = start.plusWeeks( 1 );
do {
LocalDateRange week = LocalDateRange.of( start , end );
weeks.add( week );
// Set up next loop.
start = start.plusWeeks( 1 );
end = start.plusWeeks( 1 );
} while ( ! YearMonth.from( end ).isAfter( yearMonth ) );
navMap.put( yearMonth , weeks );
}
return Collections.unmodifiableNavigableMap( navMap ); // Generally best to return immutable values.
}
}
用法:
Year year = Year.of( 2021 );
Locale locale = new Locale( "pt" , "BR" );
NavigableMap < YearMonth, List < LocalDateRange > > map = WeeklyCalendar.calculate( year , locale );
LocalDateRange weekOneOfMarch2021 = map.get( YearMonth.of( 2021 , Month.MARCH ) ).get( 0 ); // Lists use annoying zero-based counting, index number.
当运行.
map = {2021-01=[2020-12-27/2021-01-03, 2021-01-03/2021-01-10, 2021-01-10/2021-01-17, 2021-01-17/2021-01-24, 2021-01-24/2021-01-31], 2021-02=[2021-01-31/2021-02-07, 2021-02-07/2021-02-14, 2021-02-14/2021-02-21, 2021-02-21/2021-02-28], 2021-03=[2021-02-28/2021-03-07, 2021-03-07/2021-03-14, 2021-03-14/2021-03-21, 2021-03-21/2021-03-28], 2021-04=[2021-03-28/2021-04-04, 2021-04-04/2021-04-11, 2021-04-11/2021-04-18, 2021-04-18/2021-04-25], 2021-05=[2021-04-25/2021-05-02, 2021-05-02/2021-05-09, 2021-05-09/2021-05-16, 2021-05-16/2021-05-23, 2021-05-23/2021-05-30], 2021-06=[2021-05-30/2021-06-06, 2021-06-06/2021-06-13, 2021-06-13/2021-06-20, 2021-06-20/2021-06-27], 2021-07=[2021-06-27/2021-07-04, 2021-07-04/2021-07-11, 2021-07-11/2021-07-18, 2021-07-18/2021-07-25], 2021-08=[2021-08-01/2021-08-08, 2021-08-08/2021-08-15, 2021-08-15/2021-08-22, 2021-08-22/2021-08-29], 2021-09=[2021-08-29/2021-09-05, 2021-09-05/2021-09-12, 2021-09-12/2021-09-19, 2021-09-19/2021-09-26], 2021-10=[2021-09-26/2021-10-03, 2021-10-03/2021-10-10, 2021-10-10/2021-10-17, 2021-10-17/2021-10-24, 2021-10-24/2021-10-31], 2021-11=[2021-10-31/2021-11-07, 2021-11-07/2021-11-14, 2021-11-14/2021-11-21, 2021-11-21/2021-11-28], 2021-12=[2021-11-28/2021-12-05, 2021-12-05/2021-12-12, 2021-12-12/2021-12-19, 2021-12-19/2021-12-26]}
weekOneOfMarch2021 = 2021-02-28/2021-03-07
注意 LocalDateRange#toString
如何使用开始日期的标准格式,然后是 SOLIDUS /
,然后是结束日期。
年度重叠
请注意,我们从前一年的天数开始。我们不包括日历年的最后几天。
半开
请注意,这里的周是使用半开方法定义的,其中开始是 包含 ,而结尾是 不包含 。这通常是定义时间跨度的最佳方法。我建议在整个代码库中始终如一地使用这种方法,以保持逻辑一致,从而避免错误和混淆。
全封闭
不过,如果你坚持全封闭的方式,LocalDateRange
class可以支持。请参阅 LocalDateRange.ofClosed
方法。
使用风险自负
我刚才快速编写了这段代码。所以没有保证。验证逻辑,并执行您自己的测试。
ISO 8601 周
请注意,定义一周的方法有多种。一些行业通常使用特定的定义。
有一个越来越受欢迎的国际标准:ISO 8601. That standard defines weeks因为星期一是一周的第一天,第 1 周包含日历年的第一个星期四。因此,一年由 52 或 53 个完整的星期组成,每个星期 7 天。
ThreeTen-Extra 库提供了一个 class 来表示 ISO 8601 周:YearWeek
.
我需要帮助 return 给定周的第一天(和最后一天),仅传递该月的第几周以及相应的月份和年份。
我已经在寻找使用 LocalDate 或 Calendar return 的方法,但没有找到。
我的语言环境是 PT-BR - 一周的第一天是星期日
提前致谢。
例如:
Year 2021 - Month 7 (July) - Week 1 - First day: 1 - Last Day: 3
Year 2021 - Month 7 (July) - Week 2 - First day: 4 - Last Day: 10
Year 2021 - Month 7 (July) - Week 3 - First day: 11 - Last Day: 17
Year 2021 - Month 7 (July) - Week 4 - First day: 18 - Last Day: 24
Year 2021 - Month 7 (July) - Week 5 - First day: 25 - Last Day: 31
我发现你的周历方法很有趣,想出了一个接收两个参数(月和年)并建立那个月的周历的方法:
private static Map<Integer, Integer[]> getWeekCalendar(int month, int year) {
Map<Integer, Integer[]> weekCalendar = new HashMap<>();
LocalDate date = LocalDate.of(year,month,1);
int week = 1;
LocalDate firstOfWeek = LocalDate.from(date);
while (date.getMonth().equals(Month.of(month))) {
//if it is a saturday, advance to the next week and register current week bounds
if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
weekCalendar.put(week++, new Integer[]{firstOfWeek.getDayOfMonth(), date.getDayOfMonth()});
firstOfWeek = LocalDate.from(date.plusDays(1L));
}
date = date.plusDays(1L);
}
//this one is necessary because the month may end on a Saturday
if (firstOfWeek.getMonth().equals(Month.of(month))) {
weekCalendar.put(week, new Integer[]{firstOfWeek.getDayOfMonth(), date.minusDays(1L).getDayOfMonth()});
}
return weekCalendar;
}
还有一个主要的 class 用于测试目的:
public static void main(String[] args) {
int wantedMonth = 7;
int wantedYear = 2021;
Map<Integer, Integer[]> weekCalendar = getWeekCalendar(wantedMonth, wantedYear);
weekCalendar.entrySet().stream()
.map(e -> String.format("Year %d - Month %d (%s) - Week %d - First day: %d - Last day: %d", wantedYear, wantedMonth, Month.of(wantedMonth).name(), e.getKey(), e.getValue()[0], e.getValue()[1]))
.forEach(System.out::println);
}
输出:
Year 2021 - Month 7 (JULY) - Week 1 - First day: 1 - Last day: 3
Year 2021 - Month 7 (JULY) - Week 2 - First day: 4 - Last day: 10
Year 2021 - Month 7 (JULY) - Week 3 - First day: 11 - Last day: 17
Year 2021 - Month 7 (JULY) - Week 4 - First day: 18 - Last day: 24
Year 2021 - Month 7 (JULY) - Week 5 - First day: 25 - Last day: 31
没有一个函数可以获取一个月中的第几周。
我整理了一个方法来计算一个月中的第几周。这是我的多次测试之一的测试结果。
Week 1 of July 2021 is 1 - 3
Week 2 of July 2021 is 4 - 10
Week 3 of July 2021 is 11 - 17
Week 4 of July 2021 is 18 - 24
Week 5 of July 2021 is 25 - 31
Week 6 of July 2021 is 0 - 0
Week 1 of August 2021 is 1 - 7
Week 2 of August 2021 is 8 - 14
我根据年份和月份创建了一个LocalDate
。我做了一些日期运算,得到一个月中的星期日和星期六。
这是代码。我测试了 2021 年 7 月和 8 月。它可能适用于其他月份。
import java.time.LocalDate;
public class DatesFinder {
public static void main(String[] args) {
DatesFinder df = new DatesFinder();
int[] days = df.findDays(2021, 7, 1);
System.out.println("Week 1 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 2);
System.out.println("Week 2 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 3);
System.out.println("Week 3 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 4);
System.out.println("Week 4 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 5);
System.out.println("Week 5 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 7, 6);
System.out.println("Week 6 of July 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 8, 1);
System.out.println("Week 1 of August 2021 is " + days[0] + " - " + days[1]);
days = df.findDays(2021, 8, 2);
System.out.println("Week 2 of August 2021 is " + days[0] + " - " + days[1]);
}
public int[] findDays(int year, int month, int weekNumber) {
LocalDate date = LocalDate.of(year, month, 1);
int weekday = date.getDayOfWeek().getValue();
// weekday is 1 - Monday to 7 - Sunday.
// convert to 0 - Sunday.
weekday = weekday % 7;
LocalDate sundayDate = date.minusDays(weekday);
int dayIncrement = (weekNumber - 1) * 7;
if (dayIncrement > 0) {
sundayDate = sundayDate.plusDays(dayIncrement);
}
int lowDay = sundayDate.getDayOfMonth();
LocalDate saturdayDate = sundayDate.plusDays(6L);
int highDay = saturdayDate.getDayOfMonth();
// System.out.println(date + " " + sundayDate + " " + lowDay + " " + highDay);
// Test for beginning of month
if (sundayDate.getMonth().compareTo(date.getMonth()) < 0) {
lowDay = 1;
}
// Test for end of month
if (saturdayDate.getMonth().compareTo(date.getMonth()) > 0) {
LocalDate nextMonth = date.plusMonths(1L);
nextMonth = nextMonth.minusDays(1L);
highDay = nextMonth.getDayOfMonth();
}
// Test for outside of month (weekNumber too high)
if (sundayDate.getMonth().compareTo(date.getMonth()) > 0) {
lowDay = 0;
highDay = 0;
}
int[] output = new int[2];
output[0] = lowDay;
output[1] = highDay;
return output;
}
}
java.time
java.util
日期时间 API 及其格式 API、SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*.
解决方案使用 java.time
,现代日期时间 API:
- 使用
WeekFields.of(locale).getFirstDayOfWeek()
查找一周的第一天。 - 使用
TemporalAdjusters.nextOrSame(firstDayOfWeek)
查找一周的最后一天。 - 使用
TemporalAdjusters.lastDayOfMonth()
查找该月的最后一天。
演示:
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.format.TextStyle;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getWeeks(2021, 7, new Locale("pt", "BR")));
System.out.println("---------------------------------------------------------");
System.out.println(getWeeks(2021, 2, new Locale("pt", "BR")));
System.out.println("---------------------------------------------------------");
System.out.println(getWeeks(2021, 7, new Locale("en", "GB")));
System.out.println("---------------------------------------------------------");
System.out.println(getWeeks(2021, 2, new Locale("en", "GB")));
}
static String getWeeks(int year, int month, Locale locale) {
DayOfWeek firstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek();
LocalDate firstDateOfMonth = LocalDate.of(year, month, 1);
String monthName = Month.of(month).getDisplayName(TextStyle.FULL, Locale.ENGLISH);
int lastDayOfMonth = firstDateOfMonth.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
int firstDay = 1;
int lastDayOfFirstWeek = LocalDate.of(year, month, 1).with(TemporalAdjusters.nextOrSame(firstDayOfWeek))
.getDayOfMonth();
int lastDay = lastDayOfFirstWeek == 1 ? 7 : lastDayOfFirstWeek - 1;
int i;
StringBuilder sb = new StringBuilder();
for (i = 1; i <= lastDayOfMonth / 7; i++) {
sb.append(String.format("Year %d - Month %d (%s) - Week %d - First day: %d - Last Day: %d%n", year, month,
monthName, i, firstDay, lastDay));
firstDay = lastDay + 1;
lastDay += 7;
}
if (lastDayOfFirstWeek != 1 && lastDayOfMonth >= 28)
sb.append(String.format("Year %d - Month %d (%s) - Week %d - First day: %d - Last Day: %d%n", year, month,
monthName, i, firstDay, lastDayOfMonth));
return sb.toString();
}
}
输出:
Year 2021 - Month 7 (July) - Week 1 - First day: 1 - Last Day: 3
Year 2021 - Month 7 (July) - Week 2 - First day: 4 - Last Day: 10
Year 2021 - Month 7 (July) - Week 3 - First day: 11 - Last Day: 17
Year 2021 - Month 7 (July) - Week 4 - First day: 18 - Last Day: 24
Year 2021 - Month 7 (July) - Week 5 - First day: 25 - Last Day: 31
---------------------------------------------------------
Year 2021 - Month 2 (February) - Week 1 - First day: 1 - Last Day: 6
Year 2021 - Month 2 (February) - Week 2 - First day: 7 - Last Day: 13
Year 2021 - Month 2 (February) - Week 3 - First day: 14 - Last Day: 20
Year 2021 - Month 2 (February) - Week 4 - First day: 21 - Last Day: 27
Year 2021 - Month 2 (February) - Week 5 - First day: 28 - Last Day: 28
---------------------------------------------------------
Year 2021 - Month 7 (July) - Week 1 - First day: 1 - Last Day: 4
Year 2021 - Month 7 (July) - Week 2 - First day: 5 - Last Day: 11
Year 2021 - Month 7 (July) - Week 3 - First day: 12 - Last Day: 18
Year 2021 - Month 7 (July) - Week 4 - First day: 19 - Last Day: 25
Year 2021 - Month 7 (July) - Week 5 - First day: 26 - Last Day: 31
---------------------------------------------------------
Year 2021 - Month 2 (February) - Week 1 - First day: 1 - Last Day: 7
Year 2021 - Month 2 (February) - Week 2 - First day: 8 - Last Day: 14
Year 2021 - Month 2 (February) - Week 3 - First day: 15 - Last Day: 21
Year 2021 - Month 2 (February) - Week 4 - First day: 22 - Last Day: 28
从 Trail: Date Time 中了解有关 modern Date-Time API* 的更多信息.
* 无论出于何种原因,如果您必须坚持Java 6 或Java 7,您可以使用ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and
年历周数
为了扩展
ThreeTen-Extra 图书馆,LocalDateRange
class
将 ThreeTen-Extra 库添加到您的项目中。这给了我们 LocalDateRange
class 将时间跨度表示为一对 LocalDate
对象。这个class提供了abuts
、contains
等很多方便的方法,在你处理周的时候可能会有帮助。
指定 Year
和 Locale
。我们根据区域设置确定一周中的第一天,如
每月循环,然后每周循环
我们使用 Month
objects returned by the Month.values
method on this enum. We combine each month with the year to get a YearMonth
对象数组循环一年中的每个月。
对于每个 YearMonth
,我们得到该月的第一天。然后我们及时回溯得到一周的第一天 (DayOfWeek
), or use the same date if it is indeed our desired day-of-week. A TemporalAdjuster
moves us along the timeline. You can write your own TemporalAdjuster
implementation, but we can find one already written for our needs here: TemporalAdjusters.previousOrSame( DayOfWeek )
.
然后我们循环计算每月的每一周,从一对 LocalDate
对象中创建一个 LocalDateRange
作为每周的开始和结束。我们将那些 LocalDateRange
个对象收集到 NavigableSet
, a TreeSet
.
我们通过将每个 YearMonth
作为键添加到 NavigableMap
(TreeMap
) 来报告我们的结果,其值为 LocalDateRange
的 NavigableSet
。
示例代码
package work.basil.datetime;
import org.threeten.extra.LocalDateRange;
import java.time.*;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.*;
public final class WeeklyCalendar {
public static final NavigableMap < YearMonth, List < LocalDateRange > > calculate ( final Year year , final Locale locale ) {
Objects.requireNonNull( year );
DayOfWeek startOfWeek = WeekFields.of( Objects.requireNonNull( locale ) ).getFirstDayOfWeek();
NavigableMap < YearMonth, List < LocalDateRange > > navMap = new TreeMap <>();
TemporalAdjuster adjuster = TemporalAdjusters.previousOrSame( startOfWeek );
for ( Month month : Month.values() ) {
List < LocalDateRange > weeks = new ArrayList <>();
YearMonth yearMonth = year.atMonth( month );
LocalDate start = yearMonth.atDay( 1 ).with( adjuster );
LocalDate end = start.plusWeeks( 1 );
do {
LocalDateRange week = LocalDateRange.of( start , end );
weeks.add( week );
// Set up next loop.
start = start.plusWeeks( 1 );
end = start.plusWeeks( 1 );
} while ( ! YearMonth.from( end ).isAfter( yearMonth ) );
navMap.put( yearMonth , weeks );
}
return Collections.unmodifiableNavigableMap( navMap ); // Generally best to return immutable values.
}
}
用法:
Year year = Year.of( 2021 );
Locale locale = new Locale( "pt" , "BR" );
NavigableMap < YearMonth, List < LocalDateRange > > map = WeeklyCalendar.calculate( year , locale );
LocalDateRange weekOneOfMarch2021 = map.get( YearMonth.of( 2021 , Month.MARCH ) ).get( 0 ); // Lists use annoying zero-based counting, index number.
当运行.
map = {2021-01=[2020-12-27/2021-01-03, 2021-01-03/2021-01-10, 2021-01-10/2021-01-17, 2021-01-17/2021-01-24, 2021-01-24/2021-01-31], 2021-02=[2021-01-31/2021-02-07, 2021-02-07/2021-02-14, 2021-02-14/2021-02-21, 2021-02-21/2021-02-28], 2021-03=[2021-02-28/2021-03-07, 2021-03-07/2021-03-14, 2021-03-14/2021-03-21, 2021-03-21/2021-03-28], 2021-04=[2021-03-28/2021-04-04, 2021-04-04/2021-04-11, 2021-04-11/2021-04-18, 2021-04-18/2021-04-25], 2021-05=[2021-04-25/2021-05-02, 2021-05-02/2021-05-09, 2021-05-09/2021-05-16, 2021-05-16/2021-05-23, 2021-05-23/2021-05-30], 2021-06=[2021-05-30/2021-06-06, 2021-06-06/2021-06-13, 2021-06-13/2021-06-20, 2021-06-20/2021-06-27], 2021-07=[2021-06-27/2021-07-04, 2021-07-04/2021-07-11, 2021-07-11/2021-07-18, 2021-07-18/2021-07-25], 2021-08=[2021-08-01/2021-08-08, 2021-08-08/2021-08-15, 2021-08-15/2021-08-22, 2021-08-22/2021-08-29], 2021-09=[2021-08-29/2021-09-05, 2021-09-05/2021-09-12, 2021-09-12/2021-09-19, 2021-09-19/2021-09-26], 2021-10=[2021-09-26/2021-10-03, 2021-10-03/2021-10-10, 2021-10-10/2021-10-17, 2021-10-17/2021-10-24, 2021-10-24/2021-10-31], 2021-11=[2021-10-31/2021-11-07, 2021-11-07/2021-11-14, 2021-11-14/2021-11-21, 2021-11-21/2021-11-28], 2021-12=[2021-11-28/2021-12-05, 2021-12-05/2021-12-12, 2021-12-12/2021-12-19, 2021-12-19/2021-12-26]}
weekOneOfMarch2021 = 2021-02-28/2021-03-07
注意 LocalDateRange#toString
如何使用开始日期的标准格式,然后是 SOLIDUS /
,然后是结束日期。
年度重叠
请注意,我们从前一年的天数开始。我们不包括日历年的最后几天。
半开
请注意,这里的周是使用半开方法定义的,其中开始是 包含 ,而结尾是 不包含 。这通常是定义时间跨度的最佳方法。我建议在整个代码库中始终如一地使用这种方法,以保持逻辑一致,从而避免错误和混淆。
全封闭
不过,如果你坚持全封闭的方式,LocalDateRange
class可以支持。请参阅 LocalDateRange.ofClosed
方法。
使用风险自负
我刚才快速编写了这段代码。所以没有保证。验证逻辑,并执行您自己的测试。
ISO 8601 周
请注意,定义一周的方法有多种。一些行业通常使用特定的定义。
有一个越来越受欢迎的国际标准:ISO 8601. That standard defines weeks因为星期一是一周的第一天,第 1 周包含日历年的第一个星期四。因此,一年由 52 或 53 个完整的星期组成,每个星期 7 天。
ThreeTen-Extra 库提供了一个 class 来表示 ISO 8601 周:YearWeek
.