Java日历年初

Java日历年初,java,calendar,Java,Calendar,我在使用Java日历时遇到了一些不愉快的问题。我想把某个星期的第一天作为日期,它一直工作得很好,直到这周是在几年之间。 如何避开它 Calendar cal = Calendar.getInstance(); cal.set(2017,0,1); cal.setFirstDayOfWeek(Calendar.MONDAY); Calendar first = (Calendar) cal.clone(); first.add(Calendar.DAY_OF_WEEK, first.getFirs

我在使用Java日历时遇到了一些不愉快的问题。我想把某个星期的第一天作为日期,它一直工作得很好,直到这周是在几年之间。 如何避开它

Calendar cal = Calendar.getInstance();
cal.set(2017,0,1);
cal.setFirstDayOfWeek(Calendar.MONDAY);
Calendar first = (Calendar) cal.clone();
first.add(Calendar.DAY_OF_WEEK,
first.getFirstDayOfWeek() - first.get(Calendar.DAY_OF_WEEK));
Calendar last = (Calendar) first.clone();
last.add(Calendar.DAY_OF_YEAR, 6);
System.out.println(first.getTime());
System.out.println(last.getTime());
输出

2017年1月2日星期一22:30:26 GMT

2017年1月8日星期日22:30:26 GMT

输出应该是

2016年12月26日星期一22:30:26 GMT

2017年1月1日星期日22:30:26 GMT


不要使用Calendar,众所周知,使用它是非常糟糕的API()。改用时间api(如果您不在java8上,请使用)

这样,您的代码将如下所示:

LocalDate ld = LocalDate.of(2017,1,1);
ld = ld.with(ChronoField.DAY_OF_WEEK, 1);
System.out.println(ld);
System.out.println(ld.plusDays(6));
如果您确实需要以
日期结束
,请使用
日期.from(ld.atStartOfDay().atZone(ZoneId.of(“UTC”)).toInstant())
转换它(假设UTC,很容易被您需要的区域替换)

tl;博士 答案是正确的。这里有一个我认为更具可读性的替代方案

LocalDate.of( 2017 , Month.JANUARY , 1 )
    .with( TemporalAdjusters.previous( DayOfWeek.MONDAY ) )
TemporalAdjuster
该接口提供操作java.time对象的类。可以在类中找到实现。理算师查找一周中某一天之前发生的事件,或者如果该日期已经是该周的某一天,则与该日期保持一致

LocalDate target = LocalDate.of( 2017 , Month.JANUARY , 1 );
LocalDate ld = target.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) );
target.toString():2017-01-01 | ld.toString():2016-12-26

如果您总是想要上一个星期一,即使日期已经是星期一,也可以使用调整器
previous

LocalDate ld = target.with( TemporalAdjusters.previous( DayOfWeek.MONDAY ) );
要获得周末,请使用调节器

LocalDate nextOrSameSunday = target.with( TemporalAdjusters.nextOrSame( DayOfWeek.SUNDAY ) );
你可以看到一周中的某一天

ZoneId z = ZoneId.of( "America/Montreal" );
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL ).withLocale( Locale.CANADA );
System.out.println( "target: " + target.format( f ) + " | ld: " + ld.format( f ) );
目标:2017年1月1日(星期日)2016年12月26日(星期一)

看这个

还要注意,和的用法。看


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

从哪里获得java.time类

  • 后来
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 该项目专门为Android采用了ThreeTen Backport(如上所述)

该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,例如、、和。

为什么您认为
first.getFirstDayOfWeek()-first.get(Calendar.DAY OfWeek)
是调整到一周开始的方法?当firstDayOfWeek为2(星期一)且dayOfWeek为1(星期日)时,您将得到
2-1=+1
,即添加1天。这就是你看到的。我将留给您来解决如何调整此逻辑以解决此问题。顺便说一句:简单地打印这些值就会告诉你这一点。问题不是因为年份的变化。你对星期几数字的理解是错误的。即使将FirstDayOfWeek设置为Monday,Monday的数量也是2,2017年1月1日起的DayOfWeek的数量是Sunday/1。因此,2-1=1和2017年1月1日+1=2017年1月2日。2017年1月2日+6=2017年1月8日。好的,谢谢你的帮助,我将使用Joda Time API,因为它能更好地解决我的特殊问题。必须使用java 8中的java.Time包。不再需要joda时间了不,这不是一个“非常糟糕的API使用”。这是一个很好的API,每个人都很快意识到OP做错了什么就证明了这一点。即使运行Java 6或7,也不需要joda时间。大部分java.time功能都在项目中进行了后移植,并在项目中进一步适用于Android。Joda Time项目现在处于维护模式,建议迁移到java.Time。@BasilBourque谢谢,我不知道。修改了答案。感谢您提供了非常详细的答案,我在我的android项目中尝试过使用Java8,但它需要最新的API。我确实用Joda Time解决了我的问题,它真的很小,只有一行代码。您提到了ThreeTenBackport,我认为在我的特殊情况下,不值得在Backport库非常小的情况下进行转换。如果您的需求实际上只有一行代码,那就足够了。通常,做约会时间工作的人会做很多。如果是这样,请更仔细地重读我答案的最后一部分。Java6&7的后端口是一个项目(ThreeTen Backport),该项目在另一个项目(ThreeTenABP)中特别适用于Android。旧的遗留类实在太糟糕了,添加一个库来替代它们是非常值得的。