tl;博士
使用LocalDate,从不使用Calendar。
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) )
.plusDays( i ) )
java.time
避免使用麻烦的旧遗留类 Calendar,因为它现在已被 java.time 类(特别是 ZonedDateTime)取代。
对于没有时间的仅日期值,请使用 LocalDate 而不是像 Calendar 或 ZonedDateTime 这样的日期+时间类型。 LocalDate 类表示没有时间和时区的仅日期值。
时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。
如果未指定时区,JVM 会隐式应用其当前默认值time zone。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。
以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 3-4 个字母的缩写,例如 EST 或 IST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为默认值可能会在任何时候在运行时被 JVM 中任何应用程序的任何线程中的任何代码更改。
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
或者指定一个日期。您可以通过数字设置月份,1 月至 12 月的编号为 1-12。
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
或者,更好的是,使用预定义的Month 枚举对象,一年中的每个月一个。提示:在整个代码库中使用这些 Month 对象,而不是仅仅使用整数,以使您的代码更具自记录性、确保有效值并提供 type-safety。
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
DayOfWeek
对于星期几,使用DayOfWeek 枚举类。它提供 7 个实例,一个用于每周的每一天,周一至周日。
DayOfWeek dow = ld.getDayOfWeek() ; // Get an enum representing the day-of-week of this date, such as `DayOfWeek.MONDAY`.
调整日期
我们需要找到上一个星期一,或者如果已经是星期一,则坚持今天的日期。要移至此类日期,请使用TemporalAdjuster 的TemporalAdjusters.previousOrSame 实现。
TemporalAdjuster ta = TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) ;
LocalDate previousOrSameMonday = ld.with( ta ) ;
通过调用LocalDate.plusDays() 来收集您想要的日期。注意 java.time 如何使用immutable objects。我们根据原始值而不是 mutating(更改)原始值获得一个新对象。
// Hard-coded `7` is the seven days in a week.
List< LocalDate > dates = new ArrayList<>( 7 ) ;
for( int i = 0 , i < 7 , i ++ ) {
LocalDate localDate = previousOrSameMonday.plusDays( i ) ;
dates.add( localDate ) ;
}
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。
更新:Joda-Time 项目现在位于maintenance mode,团队建议迁移到java.time 类。本节留给历史。
乔达时间
解决这个问题的最佳方法是什么?
最好的方法是避免使用臭名昭著的麻烦 java.util.Date 和 .Calendar 类,而是使用Joda-Time 库。 Joda-Time 适用于 Android。
Joda-Time 为没有任何时间或时区的纯日期值提供 LocalDate 类。
示例代码
这是一些使用 Joda-Time 2.3 的示例代码。
LocalDate localDate = new LocalDate( 2011, DateTimeConstants.SEPTEMBER, 4 );
LocalDate firstDateOfWeek = localDate.withDayOfWeek( DateTimeConstants.MONDAY );
for ( int i = 0; i < 7; i++ ) {
LocalDate someDateOfWeek = firstDateOfWeek.plusDays( i );
System.out.println( "someDateOfWeek: " + someDateOfWeek + " le jour de la semaine: " + someDateOfWeek.dayOfWeek().getAsText( Locale.CANADA_FRENCH ) );
}
运行时……
someDateOfWeek: 2011-08-29 le jour de la semaine: lundi
someDateOfWeek: 2011-08-30 le jour de la semaine: mardi
someDateOfWeek: 2011-08-31 le jour de la semaine: mercredi
someDateOfWeek: 2011-09-01 le jour de la semaine: jeudi
someDateOfWeek: 2011-09-02 le jour de la semaine: vendredi
someDateOfWeek: 2011-09-03 le jour de la semaine: samedi
someDateOfWeek: 2011-09-04 le jour de la semaine: dimanche
周数
额外提示:如果您想要 ISO 8601 标准定义的周数,请调用 weekOfWeekYear 方法。像这样:
int weekNumber = firstDateOfWeek.getWeekOfWeekyear();
您的日期是第 35 周。