获取本周星期一的日期

30
我们有一个实用程序,将在周一至周五之间的任何一天运行。它会更新内容管理工具中的一些文件。与该文件关联的最后修改日期应该是那个星期的星期一的日期。我编写了以下程序来检索当前周的星期一日期。但我仍然不确定这是否适用于所有情况。有没有更好的解决方案?
Calendar c = Calendar.getInstance();
c.setTime(new Date());
System.out.println(c.get(Calendar.DAY_OF_MONTH));
System.out.println(c.get(Calendar.DAY_OF_WEEK));
int mondayNo = c.get(Calendar.DAY_OF_MONTH)-c.get(Calendar.DAY_OF_WEEK)+2;
c.set(Calendar.DAY_OF_MONTH,mondayNo);
System.out.println("Date "+c.getTime());

2
你使用的是麻烦的旧日期时间类,现在已经被java.time类所取代,请注意。 - Basil Bourque
9个回答

55

我强烈推荐使用Joda Time代替(不仅仅是这个日期/时间处理),以便于你的工作:

// TODO: Consider time zones, calendars etc
LocalDate now = new LocalDate();
LocalDate monday = now.withDayOfWeek(DateTimeConstants.MONDAY);
System.out.println(monday);
请注意,由于您在此处使用的是 Joda Time 中的星期一(Monday),因此这将始终返回一个更早的日期(或相同的日期)。如果您选择了星期三(例如),那么它将从星期一或星期二“提前”到星期三。如果需要“下个星期三”或“上个星期三”,则可以始终添加或减去一周。
编辑:如果您真的想使用 java.util.Date/Calendar,可以使用以下代码:
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println("Date " + c.getTime());
你可以使用 Calendar.setFirstDayOfWeek 方法来指定一周的起始日期是星期一到星期日还是星期日到星期六;我认为设置星期几会保持在当前的一周内 - 但需要进行测试。

1
仅使用Java API不可能实现这个吗?我们使用的是CMS工具,添加新的jar包需要进行部署更改。 - Shashank Kadne
2
@ShashankKadne:当然可以,但是这样做很糟糕。如果你需要进行任何大量的基于日期的工作,使用Joda Time带来的好处将远远超过短暂的成本。 - Jon Skeet
1
@ShashankKadne:我已经编辑了我的回答,加入了java.util.Calendar代码……但我仍然建议使用Joda Time。 - Jon Skeet
3
周日不工作,会得到下周的星期一。 - acsadam0404
@adam0404:你指的是哪个例子?请注意,对于java.util.Calendar的示例,我会说明如何更改每周的第一天(如果需要的话)。 - Jon Skeet
显示剩余5条评论

31

简而言之

LocalDate previousMonday = 
    LocalDate.now( ZoneId.of( "America/Montreal" ) )
             .with( TemporalAdjusters.previous( DayOfWeek.MONDAY ) );

java.time

无论是java.util.Calendar类还是Joda-Time库,都已经被Java 8及更高版本内置的java.time框架取代。请参阅Oracle教程。许多java.time功能已经在ThreeTen-Backport中回溯到Java 6 & 7,并在ThreeTenABP中进一步适用于Android。使用现代Android工具和其"API去甜化",您不需要添加任何库。

java.time.LocalDate类表示一个仅包含日期值但没有时间和时区的类。

确定今天的日期需要一个时区,即ZoneId

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );

TemporalAdjuster接口(参见Tutorial)是操作日期时间值的强大而简单的方式。TemporalAdjusters类(注意复数形式)实现了一些非常有用的调整功能。在这里,我们使用previous(DayOfWeek)

方便的DayOfWeek枚举使指定星期几变得容易。

LocalDate previousMonday = today.with( TemporalAdjusters.previous( DayOfWeek.MONDAY ) );

如果今天是星期一,并且你想使用今天而不是一周前的日期,就调用 previousOrSame

关于java.time

java.time框架内置于Java 8及以上版本。这些类替代了老旧的日期时间类,如遗留java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参考Oracle教程。并在Stack Overflow上搜索许多示例和说明。规范是JSR 310

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

您可以直接使用数据库与java.time对象进行交换。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需使用字符串,无需使用java.sql.*类。Hibernate 5和JPA 2.2支持java.time

如何获取java.time类?

Table of which java.time library to use with which version of Java or Android

ThreeTen-Extra 项目扩展了 java.time 的附加类。该项目是 java.time 可能未来添加的试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuarter更多。请注意保留 HTML 标签。

1
Java 8 可用时最佳答案。 - peceps
2
@peceps 请重新阅读第一段。java.time可作为Java 6、Java 7和Android的后移版本使用。因此,java.time是在任何使用Java的地方最佳的方法。 - Basil Bourque

6
以下内容有效,包括月份的包装:
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
c.setTime(new Date());
int today = c.get(Calendar.DAY_OF_WEEK);
c.add(Calendar.DAY_OF_WEEK, -today+Calendar.MONDAY);
System.out.println("Date "+c.getTime());

如果您在周日(例如2月12日)编辑应用程序,则日期将是下个星期一的日期。根据您的要求(该应用程序仅在周一至周五运行),这不应该成为问题。

(+1) 用于处理极端情况。但我会采用@Jon的解决方案,因为他的代码比我的短。;) - Shashank Kadne
请注意,java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 等旧的日期时间类现在已经是遗留系统,被内置于Java 8及更高版本的java.time类所取代。请参阅Oracle的教程 - Basil Bourque

2

正如Jon所建议的那样,calendar.set方法可以使用...我已经使用以下代码片段在同一个月份和另一个月份中测试了它在星期一的情况下:

Calendar c = Calendar.getInstance();
//ensure the method works within current month
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println("Date " + c.getTime());
//go to the 1st week of february, in which monday was in january
c.set(Calendar.DAY_OF_MONTH, 1);
System.out.println("Date " + c.getTime());
//test that setting day_of_week to monday gives a date in january
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println("Date " + c.getTime());
//same for tuesday
c.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
System.out.println("Date " + c.getTime());

结果如下:
Date Mon Feb 13 10:29:41 CET 2012
Date Wed Feb 01 10:29:41 CET 2012
Date Mon Jan 30 10:29:41 CET 2012
Date Tue Jan 31 10:29:41 CET 2012

1

仅使用Java API不可能吗? 我们使用的是CMS工具,添加新的JAR文件需要进行部署更改。 - Shashank Kadne
尝试查看Joda Time 源代码。也许你可以找到使用Java API实现此功能的最佳方法... - PrimosK

0

如果您不想使用Joda Time,您可以像这样查找周数 ->(适用于Android)

public static ArrayList<String> getWeeks(int month) {

ArrayList<String> arrayListValues = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("MMMM d");

Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.MONTH, month);

int day = calendar.get(Calendar.DAY_OF_WEEK);
while (day != 1) {
  calendar.add(Calendar.DATE, 1);
  day = calendar.get(Calendar.DAY_OF_WEEK);
}

calendar.add(Calendar.DATE, -14);
String y1 = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, 6);
String y2 = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, 1);
arrayListValues.add(y1 + " - " + y2);

 y1 = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, 6);
 y2 = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, 1);
arrayListValues.add(y1 + " - " + y2);



for (int i = 0; i < 10; i++) {

  y1 = sdf.format(calendar.getTime());
  calendar.add(Calendar.DATE, 6);
  y2 = sdf.format(calendar.getTime());
  calendar.add(Calendar.DATE, 1);
  arrayListValues.add(y1 + " - " + y2);
}

return arrayListValues;
}

0

Kotlin代码。适用于较早版本的安卓系统。

    val c = Calendar.getInstance()
    c.time = Date()
    
    while (c.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
        c.add(Calendar.DAY_OF_WEEK, -1)
    }

0

对于 Android 6.0 或更高版本,请使用:

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
int day = 1, month = 7, year = 2018;
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
c.set(year, month, day);
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);  //change de day to monday
String dateMonday= sdf.format(c.getTime());

对于 Android 5.1 或更低版本,它不能正常工作,我创建了自己的方法。

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
int day = 1, month = 7, year = 2018;
Calendar c = Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.MONDAY);
//set the date with your date or the current date c.set(new Date());
c.set(year, month, day);

int diaSemana = c.get(Calendar.DAY_OF_WEEK);
for (int i = 0; i < 7; i++) {
 if (diaSemana != Calendar.MONDAY) {
     day--;
     c.set(year, month, day);
     diaSemana = c.get(Calendar.DAY_OF_WEEK);
     if (diaSemana == Calendar.MONDAY) break;
  } else {
    break;
 }
}
String dateMonday= sdf.format(c.getTime());

1
请注意,旧的日期时间类(如java.util.Datejava.util.Calendarjava.text.SimpleDateFormat)现在已经过时,被java.time类所取代。大部分java.time功能已经在ThreeTen-Backport项目中向Java 6和Java 7进行了后移植。而在ThreeTenABP中进一步适配了早期的Android (<26)。请参阅如何使用ThreeTenABP… - Basil Bourque
对于 Android 版本 8 和 9(API 级别 26 及更高版本),java.time 已内置,没有任何理由使用其他东西。对于版本 5、6 和 7,我与 @BasilBourque 一起推荐使用 ThreeTenABP,这样您仍然可以使用 java.time。并不是问题特别要求关于 Android。 - Ole V.V.

-2

如果当前周的星期一是上个月,它将无法工作...例如,如果今天是6月1日星期五...您应该使用roll方法...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接