java 如何确定通过周数和天数(周)的日期
How to determine the date passing the Week Number and Day Number (Week) in java
我需要通过传递这些参数来获取日期
- 年
- 周数(一个月内)即 1、2、3、4、5
- 天数(一周)0(星期日)到 6(星期六)
- 月份
我在 Calendar
class 中查找构造函数,但不包含这些参数。
要根据年份、周数和星期几创建日期,请使用 java.util.Calendar
实例:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2017);
cal.set(Calendar.WEEK_OF_YEAR, 26);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
从Calendar
转换为java.util.Date
:
Date date = cal.getTime();
要将 Date
转换为 java.time.LocalDateTime
使用:
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
尽管你的标签我同意 Joe C 的评论,但你应该更喜欢现代的 Java 日期和时间 API(也称为 java.time
或 JSR-310)早已过时的 Calendar
和朋友们。现代的 类 对程序员更友好,更易于使用,它们带来的惊喜更少,代码更清晰、更自然(至少当你习惯了流畅的风格时),并且更容易调试一个错误。
我不知道你是如何计算一个月的周数的。我假设第一周从该月的第一天开始并持续 7 天(因此第二周从该月的第 8 周开始,第 5 周从该月的第 29 天开始)。如果你算的不一样,请看.
我建议这个方法:
public static LocalDate weekNoAndDayToDate(Year year, Month month, int weekOfMonth, int dayOfWeek) {
// find day of week: convert from 0 (Sunday) to 6 (Saturday)
// to DayOfWeek, from 1 (Monday) to 7 (Sunday)
DayOfWeek dow;
if (dayOfWeek == 0) { // Sunday
dow = DayOfWeek.SUNDAY;
} else {
dow = DayOfWeek.of(dayOfWeek);
}
return year.atMonth(month)
.atDay(1)
.with(TemporalAdjusters.nextOrSame(dow))
.with(ChronoField.ALIGNED_WEEK_OF_MONTH, weekOfMonth);
}
我们可以用这个来做例子
LocalDate today = weekNoAndDayToDate(Year.of(2017), Month.JULY, 1, 1);
这会产生
2017-07-03
如果您需要 Date
或 GregorianCalendar
,例如您无法更改的旧 API,请执行以下操作之一:
Date oldfashiondDateObject
= Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
GregorianCalendar oldfashionedCalendarObject
= GregorianCalendar.from(today.atStartOfDay(ZoneId.systemDefault()));
在这两种情况下,不同时区的结果会有所不同(旧类的固有问题之一)。在我的电脑上,第一个产生 Date
of
Mon Jul 03 00:00:00 CEST 2017
第二个产生 GregorianCalendar
等于同一时间点。
如,您需要定义一周从哪一天开始,以及必须将第多少天视为第一周。
例如,ISO-8601 标准认为:
- 星期一是一周的第一天。
- 第一周最少天数:标准是第一周至少需要4天
月份分为几个时期,每个时期从定义的一周的第一天开始。同一个月中最早的时期如果少于最小天数则称为周0
,如果至少有最小天数则称为周1
。
根据您定义它们的方式,您可能会得到不同的结果。考虑 2017 年 7 月的日历:
July 2017
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
如果我们考虑 ISO 的定义,我们有:
- 第零周 - 2017-07-01 至 2017-07-02
- 第 1 周:从 2017-07-03 到 2017-07-09
- 第 2 周:从 2017-07-10 到 2017-07-16
- 第 3 周:从 2017-07-17 到 2017-07-22
- 第 4 周:从 2017-07-23 到 2017-07-30
- 第 5 周:2017-07-31
如果我们将一周的第一天设为星期日,将第一周的最少天数设为 1,则我们有:
- 第 1 周:2017-07-01
- 第 2 周:从 2017-07-02 到 2017-07-08
- 第 3 周:从 2017-07-09 到 2017-07-15
- 第 4 周:从 2017-07-16 到 2017-07-21
- 第 5 周:从 2017-07-22 到 2017-07-29
- 第 6 周:从 2017-07-30 到 2017-07-31
由于已经发布了 Calendar
的解决方案,我将使用新的 API 编写一个解决方案。如果您使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it ).
下面的代码适用于两者。
唯一的区别是 包名称 (在 Java 8 中是 java.time
而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes 和方法 names 是相同的。
我正在使用 DateTimeFormatter
,因为它需要所有字段(月、年、星期几和星期几)并相应地解析日期,创建一个 LocalDate
(其中有day/month/year 字段)。我也在使用 WeekFields
class,它可以配置为使用不同的周定义(第一天和第一周的最少天数)
还有一点调整将星期日视为零:
public LocalDate getDate(int weekOfMonth, int dayOfWeek, int month, int year) {
// you can customize your week definition (first day of week and mininum days in first week)
WeekFields wf = WeekFields.of(DayOfWeek.SUNDAY, 2);
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// week of month, using week definition from WeekFields
.appendValue(wf.weekOfMonth()).appendPattern(" ")
// day of week
.appendValue(ChronoField.DAY_OF_WEEK)
// month and year
.appendPattern(" M/yyyy")
// create formatter
.toFormatter();
return LocalDate.parse(weekOfMonth + " " +
// Sunday is 0, adjusting value
(dayOfWeek == 0 ? 7 : dayOfWeek) + " " + month + "/" + year, fmt);
}
使用此代码(一周从星期日开始,并且需要 2 天才能被视为第一周 - 否则周将为零,如上面的第一个示例):
LocalDate d = getDate(1, 6, 7, 2017);
d
将是 2017-07-08
(2017 年 7 月第 1 周的星期六)。
如果要使用 ISO 8601 定义,请使用常量 WeekFields.ISO
而不是使用 WeekFields.of()
方法。
与一样,也可以不创建格式化程序来完成:获取月份的第一个dayOfWeek
并将其调整为所需的weekOfMonth
:
public LocalDate getDate(int weekOfMonth, int dayOfWeek, int month, int year) {
// you can customize your week definition (first day of week and mininum days in first week)
WeekFields wf = WeekFields.of(DayOfWeek.SUNDAY, 2);
// Sunday is 0, adjusting value
DayOfWeek dow = DayOfWeek.of(dayOfWeek == 0 ? 7 : dayOfWeek);
// get the first weekday of the month
LocalDate first = LocalDate.of(year, month, 1).with(TemporalAdjusters.nextOrSame(dow));
// check in which week this date is
int week = first.get(wf.weekOfMonth());
// adjust to weekOfMonth
return first.plusWeeks(weekOfMonth - week);
}
它的工作方式完全相同,但不需要格式化程序 - 我测试了从 1600 年到 2100 年的日期,它得到了相同的结果。
PS: Calendar
也通过方法 setFirstDayOfWeek()
和 setMinimalDaysInFirstWeek()
进行了类似的配置。您可以检查调用相应 get
方法的默认配置。
我需要通过传递这些参数来获取日期
- 年
- 周数(一个月内)即 1、2、3、4、5
- 天数(一周)0(星期日)到 6(星期六)
- 月份
我在 Calendar
class 中查找构造函数,但不包含这些参数。
要根据年份、周数和星期几创建日期,请使用 java.util.Calendar
实例:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2017);
cal.set(Calendar.WEEK_OF_YEAR, 26);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
从Calendar
转换为java.util.Date
:
Date date = cal.getTime();
要将 Date
转换为 java.time.LocalDateTime
使用:
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
尽管你的标签我同意 Joe C 的评论,但你应该更喜欢现代的 Java 日期和时间 API(也称为 java.time
或 JSR-310)早已过时的 Calendar
和朋友们。现代的 类 对程序员更友好,更易于使用,它们带来的惊喜更少,代码更清晰、更自然(至少当你习惯了流畅的风格时),并且更容易调试一个错误。
我不知道你是如何计算一个月的周数的。我假设第一周从该月的第一天开始并持续 7 天(因此第二周从该月的第 8 周开始,第 5 周从该月的第 29 天开始)。如果你算的不一样,请看
我建议这个方法:
public static LocalDate weekNoAndDayToDate(Year year, Month month, int weekOfMonth, int dayOfWeek) {
// find day of week: convert from 0 (Sunday) to 6 (Saturday)
// to DayOfWeek, from 1 (Monday) to 7 (Sunday)
DayOfWeek dow;
if (dayOfWeek == 0) { // Sunday
dow = DayOfWeek.SUNDAY;
} else {
dow = DayOfWeek.of(dayOfWeek);
}
return year.atMonth(month)
.atDay(1)
.with(TemporalAdjusters.nextOrSame(dow))
.with(ChronoField.ALIGNED_WEEK_OF_MONTH, weekOfMonth);
}
我们可以用这个来做例子
LocalDate today = weekNoAndDayToDate(Year.of(2017), Month.JULY, 1, 1);
这会产生
2017-07-03
如果您需要 Date
或 GregorianCalendar
,例如您无法更改的旧 API,请执行以下操作之一:
Date oldfashiondDateObject
= Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
GregorianCalendar oldfashionedCalendarObject
= GregorianCalendar.from(today.atStartOfDay(ZoneId.systemDefault()));
在这两种情况下,不同时区的结果会有所不同(旧类的固有问题之一)。在我的电脑上,第一个产生 Date
of
Mon Jul 03 00:00:00 CEST 2017
第二个产生 GregorianCalendar
等于同一时间点。
如
例如,ISO-8601 标准认为:
- 星期一是一周的第一天。
- 第一周最少天数:标准是第一周至少需要4天
月份分为几个时期,每个时期从定义的一周的第一天开始。同一个月中最早的时期如果少于最小天数则称为周0
,如果至少有最小天数则称为周1
。
根据您定义它们的方式,您可能会得到不同的结果。考虑 2017 年 7 月的日历:
July 2017
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
如果我们考虑 ISO 的定义,我们有:
- 第零周 - 2017-07-01 至 2017-07-02
- 第 1 周:从 2017-07-03 到 2017-07-09
- 第 2 周:从 2017-07-10 到 2017-07-16
- 第 3 周:从 2017-07-17 到 2017-07-22
- 第 4 周:从 2017-07-23 到 2017-07-30
- 第 5 周:2017-07-31
如果我们将一周的第一天设为星期日,将第一周的最少天数设为 1,则我们有:
- 第 1 周:2017-07-01
- 第 2 周:从 2017-07-02 到 2017-07-08
- 第 3 周:从 2017-07-09 到 2017-07-15
- 第 4 周:从 2017-07-16 到 2017-07-21
- 第 5 周:从 2017-07-22 到 2017-07-29
- 第 6 周:从 2017-07-30 到 2017-07-31
由于已经发布了 Calendar
的解决方案,我将使用新的 API 编写一个解决方案。如果您使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it
下面的代码适用于两者。
唯一的区别是 包名称 (在 Java 8 中是 java.time
而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes 和方法 names 是相同的。
我正在使用 DateTimeFormatter
,因为它需要所有字段(月、年、星期几和星期几)并相应地解析日期,创建一个 LocalDate
(其中有day/month/year 字段)。我也在使用 WeekFields
class,它可以配置为使用不同的周定义(第一天和第一周的最少天数)
还有一点调整将星期日视为零:
public LocalDate getDate(int weekOfMonth, int dayOfWeek, int month, int year) {
// you can customize your week definition (first day of week and mininum days in first week)
WeekFields wf = WeekFields.of(DayOfWeek.SUNDAY, 2);
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// week of month, using week definition from WeekFields
.appendValue(wf.weekOfMonth()).appendPattern(" ")
// day of week
.appendValue(ChronoField.DAY_OF_WEEK)
// month and year
.appendPattern(" M/yyyy")
// create formatter
.toFormatter();
return LocalDate.parse(weekOfMonth + " " +
// Sunday is 0, adjusting value
(dayOfWeek == 0 ? 7 : dayOfWeek) + " " + month + "/" + year, fmt);
}
使用此代码(一周从星期日开始,并且需要 2 天才能被视为第一周 - 否则周将为零,如上面的第一个示例):
LocalDate d = getDate(1, 6, 7, 2017);
d
将是 2017-07-08
(2017 年 7 月第 1 周的星期六)。
如果要使用 ISO 8601 定义,请使用常量 WeekFields.ISO
而不是使用 WeekFields.of()
方法。
与dayOfWeek
并将其调整为所需的weekOfMonth
:
public LocalDate getDate(int weekOfMonth, int dayOfWeek, int month, int year) {
// you can customize your week definition (first day of week and mininum days in first week)
WeekFields wf = WeekFields.of(DayOfWeek.SUNDAY, 2);
// Sunday is 0, adjusting value
DayOfWeek dow = DayOfWeek.of(dayOfWeek == 0 ? 7 : dayOfWeek);
// get the first weekday of the month
LocalDate first = LocalDate.of(year, month, 1).with(TemporalAdjusters.nextOrSame(dow));
// check in which week this date is
int week = first.get(wf.weekOfMonth());
// adjust to weekOfMonth
return first.plusWeeks(weekOfMonth - week);
}
它的工作方式完全相同,但不需要格式化程序 - 我测试了从 1600 年到 2100 年的日期,它得到了相同的结果。
PS: Calendar
也通过方法 setFirstDayOfWeek()
和 setMinimalDaysInFirstWeek()
进行了类似的配置。您可以检查调用相应 get
方法的默认配置。