根据Java 8中的LocalDate.now()获取一周的第一天的日期

时间:2015-02-11 09:28:04

标签: java java-8

我希望根据LocalDate.now()获取一周中第一天的日期。使用JodaTime可以实现以下功能,但似乎已从Java 8中的新Date API中删除。

LocalDate now = LocalDate.now();
System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY));

我无法拨打带有DayOfWeek()',因为它不存在。

所以我的问题是:如何根据某些LocalDate获取一周中第一天的日期?

9 个答案:

答案 0 :(得分:64)

请注意,表达式System.out.println(now.with(DayOfWeek.MONDAY))与区域设置无关,因为它使用ISO-8601,因此它总是向后跳到上周一(或者在星期一停留,以防日期指向星期一)。

因此在美国或其他一些国家/地区 - 星期日开始一周 - 它可能无法正常工作 - now.with(DayOfWeek.MONDAY) 不会向前跳到星期一,以防日期点到星期天。

如果您需要解决这些问题,最好使用本地化字段WeekFields.dayOfWeek()

LocalDate now = LocalDate.now();
TemporalField fieldISO = WeekFields.of(Locale.FRANCE).dayOfWeek();
System.out.println(now.with(fieldISO, 1)); // 2015-02-09 (Monday)

TemporalField fieldUS = WeekFields.of(Locale.US).dayOfWeek();
System.out.println(now.with(fieldUS, 1)); // 2015-02-08 (Sunday)

另一个例子是由于下面的评论:

LocalDate ld = LocalDate.of(2017, 8, 18); // Friday as original date

System.out.println(
    ld.with(DayOfWeek.SUNDAY)); // 2017-08-20 (2 days later according to ISO)

// Now let's again set the date to Sunday, but this time in a localized way...
// the method dayOfWeek() uses localized numbering (Sunday = 1 in US and = 7 in France)

System.out.println(ld.with(WeekFields.of(Locale.US).dayOfWeek(), 1L)); // 2017-08-13
System.out.println(ld.with(WeekFields.of(Locale.FRANCE).dayOfWeek(), 7L)); // 2017-08-20

美国的例子清楚地表明,居住在美国的人会期望持续到下周日,因为周日被视为美国的第一天。简单的基于ISO的表达式with(DayOfWeek.SUNDAY)忽略了这个本地化问题。

答案 1 :(得分:15)

尝试

System.out.println(now.with(DayOfWeek.MONDAY));

答案 2 :(得分:3)

尽管有以前的答案,我仍然需要深入研究Java8正在做什么,所以我发现这是最直观的方法:

  

LocalDate实现Temporal

     

with(TemporalField field, long newValue)

     

返回与此对象相同类型的对象,并更改指定的字段。

因此,我们必须告诉我们要更改的LocalDate的哪个日期部分(DAY_OF_WEEK)并更改为什么值。

如果您怀疑本周的日期可能从0到6或从1到7计算:

    System.out.printf("first day of week (0 or 1) == %d \n",
            ChronoField.DAY_OF_WEEK.range().getMinimum());
first day of week (0 or 1) == 1 

我必须确定我的JDK提供的默认值 - YMMV:

    System.out.printf("default zone offset==[%s]\n",
            ZoneId.systemDefault());
    System.out.printf("1st day of week==%s\n",
            WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
default zone offset==[Europe/London]
1st day of week==MONDAY

所以如果我根据这些默认值执行一些代码,就像这样:

    LocalDate localDate = LocalDate.now();
    System.out.printf("localDate == %s \n", localDate);
    System.out.printf("localdate first day of week == %s (%s) \n",
            localDate.with(ChronoField.DAY_OF_WEEK, 1),
            localDate.with(ChronoField.DAY_OF_WEEK, 1).getDayOfWeek());
localDate == 2017-10-24 
localdate first day of week == 2017-10-23 (MONDAY) 

然后Java与ChronoField.DAY_OF_WEEK一起使用,它不仅定义了我们想要改变的日期的哪一部分,而且还定义了如何改变它。

因此,如果我们希望我们的代码处理用户指定为一周中第一天的任何内容,我们使用WeekFields.of()工厂方法创建自己的基于周计算的方式的定义。

使用此功能,我们可以将自己的dayOfWeek参数传递给with(),按照我们想要的方式进行日期计算:

    TemporalField myWeek = WeekFields.of(DayOfWeek.SUNDAY, 1).dayOfWeek();
    System.out.printf("configured localdate first day of week == %s (%s) \n",
            localDate.with(myWeek, 1),
            localDate.with(myWeek, 1).getDayOfWeek());
configured localdate first day of week == 2017-10-22 (SUNDAY) 

要获得更多信息,请查看LocalDate.with()中的代码,这非常有趣。

答案 3 :(得分:2)

感谢come from中的this question

Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day !
        cal.clear(Calendar.MINUTE);
        cal.clear(Calendar.SECOND);
        cal.clear(Calendar.MILLISECOND);

        // get start of this week in milliseconds
        cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
        System.out.println("Start of this week:       " + cal.getTime());
        System.out.println("... in milliseconds:      " + cal.getTimeInMillis());

答案 4 :(得分:1)

正如Ray所说的correct Answer,您可以致电with并传递DayOfWeek枚举。

时区

请注意,时区对于确定“今天”的日期至关重要。在任何时候,日期都会因您站在地球上的位置而异。

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate firstDayOfThisWeek = LocalDate.now ( zoneId ).with ( DayOfWeek.MONDAY );

如果未指定时区,则会以静默方式应用JVM的当前默认时区。注意:默认情况下,运行期间可随时更改更好地指定your desired/expected time zone

ZonedDateTime

您可以将时区(ZoneId)应用到LocalDate,以获得代表一周中第一时刻的ZonedDateTime

ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );

答案 5 :(得分:1)

LocalDate似乎没有这个,但WeekFields(来自java-8 API)确实(here)。所以你可以这样做:

WeekFields.of(Locale.getDefault()).firstDayOfWeek.value

这将返回星期的第一天的值,从1开始作为星期一,以7作为星期日结束。

使用示例(在Kotlin中),获取一个设置了dayOfWeek的新LocalDate,时间倒退而不是前进:

/**@param targetDayOfWeek day of week to go to, starting from 1 as Monday (and 7 is Sunday) */
fun LocalDate.minusDaysToDayOfWeek(targetDayOfWeek: Int = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value): LocalDate {
    //conversion so that Sunday is 0, Monday is 1, etc:
    val diffDays = (dayOfWeek.value % 7) - (targetDayOfWeek % 7)
    val result = when {
        diffDays == 0 -> this
        diffDays < 0 -> minusDays((7 + diffDays).toLong())
        else -> minusDays(diffDays.toLong())
    }
    return result
}

输入输出示例:

2017-12-31 -> 2017-12-31
2018-01-01 -> 2017-12-31
2018-01-02 -> 2017-12-31
2018-01-03 -> 2017-12-31
2018-01-04 -> 2017-12-31
2018-01-05 -> 2017-12-31
2018-01-06 -> 2017-12-31
2018-01-07 -> 2018-01-07
2018-01-08 -> 2018-01-07
2018-01-09 -> 2018-01-07
2018-01-10 -> 2018-01-07
2018-01-11 -> 2018-01-07
2018-01-12 -> 2018-01-07
2018-01-13 -> 2018-01-07
2018-01-14 -> 2018-01-14
2018-01-15 -> 2018-01-14

这是一个示例函数,可以及时推进到目标星期几:

fun LocalDate.plusDaysToDayOfWeek(targetDayOfWeek: Int = getLastDayOfWeek()): LocalDate {
    val diffDays = (targetDayOfWeek % 7) - (dayOfWeek.value % 7)
    val result = when {
        diffDays == 0 -> this
        diffDays < 0 -> plusDays((7 + diffDays).toLong())
        else -> plusDays(diffDays.toLong())
    }
    return result
}

/**@return the  last day of week, when 1 is Monday ... 7 is Sunday) */
@JvmStatic
fun getLastDayOfWeek(firstDayOfWeek: DayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek): Int {
    return when (firstDayOfWeek) {
        DayOfWeek.MONDAY -> DayOfWeek.SUNDAY.value
        else -> firstDayOfWeek.value - 1
    }
}
顺便说一句,奇怪的是我认为新API背后的代码实际上使用了Calendar类......

如果你不喜欢使用dayOfWeek用于LocalDate(和我一样),而你更喜欢用于Calendar的那个,你可以使用这些简单的转换器:

fun DayOfWeek.toCalendarDayOfWeek(): Int {
    return when (this) {
        DayOfWeek.SATURDAY -> Calendar.SATURDAY
        else -> (this.value + 1) % 7
    }
}

@JvmStatic
fun convertLocalDateDayOfWeekToCalendarDayOfWeek(localDateDayOfWeek: Int): Int {
    return when (localDateDayOfWeek) {
        DayOfWeek.SATURDAY.value -> Calendar.SATURDAY
        else -> (localDateDayOfWeek + 1) % 7
    }
}

@JvmStatic
fun convertFromCalendarDayOfWeekToLocalDateDayOfWeek(calendarDayOfWeek: Int): Int {
    return when (calendarDayOfWeek) {
        Calendar.SUNDAY -> DayOfWeek.SUNDAY.value
        else -> calendarDayOfWeek - 1
    }
}

答案 6 :(得分:0)

有了Joda Time,你怎么看

now.toString("EEEE", locale)

答案 7 :(得分:0)

如果我想将星期一作为当前一周的第一天,它对我有用:

LocalDate mondayDate = LocalDate.now().with(WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());

答案 8 :(得分:0)

wsCopy.Cells(lCopyLastRow, "A").Resize(1, 8).Copy _
      wsDest.Range("A" & lDestLastRow)