我需要通过传递这些参数来获取日期
我在Calendar
类中查找了一个构造函数,但不包含这些参数。
答案 0 :(得分:2)
尽管你的标签我同意Joe C的评论,你应该更喜欢现代的Java日期和时间API(AKA称为java.time
或JSR-310)而不是过时的Calendar
和朋友。现代课程更友好,更易于使用,它们带来更少的惊喜,导致更清晰和更自然的代码(至少当你习惯了流畅的风格),并且如果你犯错误就更容易调试。 / p>
我不知道你如何计算这个月的周数。我假设第一周从本月的第一周开始并持续7天(所以第二周从第8周开始,第5周从第29天开始)。如果您的计算方式不同,请参阅Hugo’s answer。
我建议这种方法:
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
Mon Jul 03 00:00:00 CEST 2017
第二个产生的GregorianCalendar
等于同一时间点。
答案 1 :(得分:1)
要使用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());
答案 2 :(得分:1)
作为@Ole V.V. explained,您需要定义一周开始的日期,以及第一周必须考虑的天数。
例如,ISO-8601标准考虑:
月份分为每个时段从定义的第一天开始的时段。同一个月的最早期间如果小于最小天数,则称为周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的定义,我们有:
如果我们将星期的第一天视为星期日,将第一周的最小天数视为1,我们有:
由于已发布Calendar
的解决方案,我将使用新API编写一个。如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs。
如果您使用的是 Java< = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,有ThreeTenABP(更多关于如何使用它here)。
以下代码适用于两者。
唯一的区别是包名称(在Java 8中为java.time
而在ThreeTen Backport(或Android的ThreeTenABP中)为org.threeten.bp
),但类和方法名称是一样的。
我正在使用DateTimeFormatter
因为它占用了所有字段(月,年,星期和星期几)并相应地解析了这一天,创建了LocalDate
(其中有一天) /月/年字段)。我也在使用WeekFields
类,可以将其配置为使用不同的周定义(第一天的第一天和最小天数)
还有一点调整将周日视为零:
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()
方法。
作为@Ole V.V. suggested in the comments,也可以在不创建格式化程序的情况下完成:获取当月的第一个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
方法的默认配置。