我有这个功能:
/**
* @return From november to december -> current year +1 else current year
*/
public static int getCurrentScolYear () {
int month = Calendar.getInstance().get(Calendar.MONTH);
if ( month == NOVEMBER || month == DECEMBER) {
return Calendar.getInstance().get(Calendar.YEAR) +1;
}
return Calendar.getInstance().get(Calendar.YEAR);
}
Run Code Online (Sandbox Code Playgroud)
这用于计算 scolar 年(从 11 月开始)。
我想通过更改“当前时间”在 Junit 测试中对此进行测试。所以我可以测试不同日期的结果。
我找到了这个线程,但它似乎过于复杂:java: how to mock Calendar.getInstance()?
有没有一个简单的解决方案来测试这个?
可怕的Calendar类在几年前被java.time类取代,特别是ZonedDateTime. 没有理由Calendar再次使用。
下面是我替换你的代码。
我们可以返回类型安全且不言自明的java.time.Year对象,而不仅仅是一个整数。但这会产生误导,因为该类被明确定义为符合 ISO 8601 的年份编号。
我建议你定义自己的AcademicYear类。传递此类的对象以使您的代码更具自文档性、提供类型安全性并确保有效值。类似于以下课程。
这个自定义类还为您的静态方法提供了一个家。
此类遵循java.time.Year该类的指导原则,包括其命名约定。
一个学年实际上是两年的数字,开始年份和下一个停止年份。下面的类存储两者。
示例用法:
AcademicYear.now().getDisplayName() // 2017-2018
Run Code Online (Sandbox Code Playgroud)
或者
AcademicYear.now().getValueStart() // First year of the two-year range, such as 2018 of the year 2018-2019.
Run Code Online (Sandbox Code Playgroud)
我在没有测试的情况下把这门课扔到了一起。所以使用它作为指导,而不是生产代码。
AcademicYear.javapackage com.basilbourque.example;
import java.time.*;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
// This class follows the lead of the `java.time.Year` class.
// See JavaDoc: https://docs.oracle.com/javase/10/docs/api/java/time/Year.html
// See OpenJDK source-code: http://hg.openjdk.java.net/jdk10/master/file/be620a591379/src/java.base/share/classes/java/time/Year.java
// This class follows the immutable objects pattern. So only getter accessor methods, no setters.
public class AcademicYear {
// Statics
static public int FIRST_YEAR_LIMIT = 2017;
static public int FUTURE_YEARS_LIMIT = 10;
static public Set < Month > academicYearStartingMonths = EnumSet.of( Month.NOVEMBER , Month.DECEMBER );
// Members
private int academicYearNumberStart;
// Constructor
private AcademicYear ( int academicYearNumberStart ) {
if ( academicYearNumberStart < AcademicYear.FIRST_YEAR_LIMIT ) {
throw new IllegalArgumentException( "Received a year number: " + academicYearNumberStart + " that is too long ago (before " + AcademicYear.FIRST_YEAR_LIMIT + "). Message # c5fd65c1-ed10-4fa1-96db-77d08ef1d97e." );
}
if ( academicYearNumberStart > Year.now().getValue() + AcademicYear.FUTURE_YEARS_LIMIT ) {
throw new IllegalArgumentException( "Received a year number that is too far in the future, over " + AcademicYear.FUTURE_YEARS_LIMIT + " away. Message # 8581e4ca-afb3-4ab7-8849-9b02c434eb4c." );
}
this.academicYearNumberStart = academicYearNumberStart;
}
public static AcademicYear of ( int academicYearNumberStart ) {
return new AcademicYear( academicYearNumberStart );
}
public int getValueStart ( ) {
return this.academicYearNumberStart;
}
public int getValueStop ( ) {
return ( this.academicYearNumberStart + 1 );
}
public String getDisplayName ( ) {
String s = this.academicYearNumberStart + "-" + ( this.academicYearNumberStart + 1 );
return s;
}
// ------| `Object` |---------------------
@Override
public String toString ( ) {
return "AcademicYear{ " +
"academicYearNumberStart=" + academicYearNumberStart +
" }";
}
@Override
public boolean equals ( Object o ) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;
AcademicYear that = ( AcademicYear ) o;
return this.getDisplayName().equals( that.getDisplayName() );
}
@Override
public int hashCode ( ) {
return Objects.hash( this.getDisplayName() );
}
// -----------| Factory methods |-------------------
static public AcademicYear now ( ) { // I think making ZoneId optional is a poor design choice, but I do so here to mimic `java.time.Year`.
AcademicYear ay = AcademicYear.now( Clock.systemDefaultZone() );
return ay;
}
static public AcademicYear now ( ZoneId zoneId ) {
// Determine the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
AcademicYear ay = AcademicYear.now( Clock.system( zoneId ) );
return ay;
}
static public AcademicYear now ( Clock clock ) {
final LocalDate localDate = LocalDate.now( clock );
AcademicYear ay = AcademicYear.from( localDate );
return ay;
}
static public AcademicYear from ( LocalDate localDate ) {
Objects.requireNonNull( localDate , "Received a null `LocalDate` object. Message # 558dd5e8-5cff-4c6e-b0f8-40dbcd76a753." );
// Extract the month of the specified date. If not Nov or Dec, subtract one from the year.
int y = localDate.getYear();
// If not November or December, subtract 1.
int startingYear;
if ( ! academicYearStartingMonths.contains( localDate.getMonth() ) ) {
startingYear = ( y - 1 );
} else {
startingYear = y;
}
AcademicYear ay = AcademicYear.of( startingYear );
return ay;
}
}
Run Code Online (Sandbox Code Playgroud)
ZoneId另一个变化是ZoneId时区的必需参数。
时区对于确定日期至关重要,因此是确定年份。对于任何给定时刻,日期因地区而异。例如,在法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天” 。
如果未指定时区,JVM 会隐式应用其当前默认时区。该默认值可能会在运行时随时更改(!),因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。
以、、 或等格式指定正确的时区名称。永远不要使用 2-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST
另一个变化是我们有两组方法而不是一个方法。
一种方法,AcademicYear.from负责进行 11 月调整的逻辑。您将 a 传递LocalDate给此方法。
其他方法, 的三种变体AcademicYear.now,负责确定当前时刻,调整到指定的时区,并提取仅日期LocalDate对象。也就是说LocalDate然后对象被传递到另一个方法。
Clock 用于单元测试对于测试,您可以将now一个Clock实例传递给方法变体之一,该实例可以根据需要改变时间。本Clock类提供了几个时钟与行为改变,比如在固定的时间点,当前时刻加/减一个跨度的时间,和改变节奏在时钟在您指定的粒度蜱如每5分钟。
有关改变的Clock行为的更多信息,请参阅我对另一个问题的回答。
例子:
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ; // 2018-01-23
LocalTime lt = LocalTime.of( 8 , 0 ) ; // 8 AM.
Instant instant = ZonedDateTime.of( ld , lt , z ).toInstant() ;
Clock c = Clock.fixed( instant , z ) ;
AcademicYear ay = AcademicYear.now( c ) ;
Run Code Online (Sandbox Code Playgroud)
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
从哪里获得 java.time 类?
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval,YearWeek,YearQuarter,和更多。
| 归档时间: |
|
| 查看次数: |
1029 次 |
| 最近记录: |