T+1日期计算。通过@ConfigurationProperties方式实现
前言:示例代码为T+1日期计算工具类,通过读取写入配置文件的节假日日期实时计算T+1日期;
TradingDayProperties.java
@ConfigurationProperties(prefix = "account.constant.trading")
public class TradingDayProperties {
private String holidays;
private String workdays;
}
TradingDayConfig.java
@Configuration
@EnableConfigurationProperties(TradingDayProperties.class)
public class TradingDayConfig {
@Bean
public TradingDayProperties tradingDayProperties(){
log.info("初始化tradingDayProperties");
return new TradingDayProperties();
}
@Bean(value = "tradingDayUtil",initMethod = "init")
public TradingDayUtil getTradingDayUtils(){
log.info("初始化tradingDayUtil");
TradingDayUtil tradingDayUtil = new TradingDayUtil();
tradingDayUtil.setParam(tradingDayProperties());
return tradingDayUtil;
}
}
TradingDayUtil.java
// @Todo 使用Calendar会出现日期错乱问题,错误发生类:java.util.GregorianCalendar 一旦调用到getTimeInMillis()函数时会发生触发updateTime()函数修改日期,未查明原应
@Data
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class TradingDayUtil {
private TradingDayProperties param;
// private List<Calendar[]> holidayArray = new ArrayList<>();
//
// private List<Calendar[]> workdayArray = new ArrayList<>();
private List<long[]> holidayArray = new ArrayList<>();
private List<long[]> workdayArray = new ArrayList<>();
private int[] a = {1, 7}; // 六日
private SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
public void init(){
try{
String[] dayArray = param.getHolidays().split(",");
for(String item: dayArray){
// Calendar[] dateArray;
long[] dateArray;
String[] split = item.split("-");
Long calendar = stringToCalendar(split[0]);
calendar -= 24 * 60 * 1000;
// dateArray = new Calendar[]{calendar, stringToCalendar(split[split.length - 1])};
dateArray = new long[]{calendar,stringToCalendar(split[split.length - 1])};
holidayArray.add(dateArray);
}
String[] workDayArray = param.getWorkdays().split(",");
for (String item: workDayArray){
// Calendar[] dateArray;
long[] dateArray;
String[] split = item.split("-");
Long calendar = stringToCalendar(split[0]);
// dateArray = new Calendar[]{stringToCalendar(split[0]), stringToCalendar(split[split.length - 1])};
dateArray = new long[]{stringToCalendar(split[0]), stringToCalendar(split[split.length - 1])};
workdayArray.add(dateArray);
}
log.info("节假日参数处理完成");
}catch (Exception e){
log.error("节假日参数处理异常",e);
}
}
public Date getT1(){
return getT1(new Date());
}
/**
* 计算T+1
* @param tradingDay
* @return T+1日期
*/
public Date getT1(Date tradingDay){
log.info("T+1日期计算参数:{}", tradingDay);
Calendar instance = Calendar.getInstance();
instance.clear();
instance.setTime(tradingDay);
instance.set(Calendar.HOUR_OF_DAY, 0);
instance.set(Calendar.MINUTE, 0);
instance.set(Calendar.SECOND, 0);
instance.set(Calendar.MILLISECOND,0);
Calendar t1 = Calendar.getInstance();
// Optional<Calendar[]> first = holidayArray.stream().filter(item -> item[0].getTimeInMillis() <= instance.getTimeInMillis() && item[1].getTimeInMillis() > instance.getTimeInMillis()).findFirst();
Optional<long[]> first = holidayArray.stream().filter(item -> (item[0] < instance.getTimeInMillis() && item[1] > instance.getTimeInMillis()) || (item[0] == instance.getTimeInMillis() || item[1] == instance.getTimeInMillis())).findFirst();
// 交易日期发生在节假日或节假日前一天, T+1 日期为节假日结束后一天
if (first.isPresent()){
// Date time = first.get()[1].getTime();
Date time = new Date(first.get()[1]);
t1.setTime(time);
t1.add(Calendar.DAY_OF_MONTH, 1);
}else{
// 交易日第二天如果在周六日且不为加班日则下周一才是T+1
t1 = instance;
t1.add(Calendar.DAY_OF_YEAR, 1);
int weekDay = t1.get(Calendar.DAY_OF_WEEK);
if (!isInWorkdays(t1.getTimeInMillis()) && ArrayUtils.contains(a, weekDay)) {
t1.add(Calendar.DAY_OF_MONTH,weekDay == 1 ? 1 : 9 - weekDay);
}
}
log.info("T+1日期计算结果:{}", t1.getTime());
return t1.getTime();
}
/**
* 判断是否加班日
* @param calendar
* @return
*/
private boolean isInWorkdays(long calendar){
// Optional<Calendar[]> first = workdayArray.stream().filter(item -> !calendar.before(item[0]) && !item[1].after(calendar)).findFirst();
Optional<long[]> first = workdayArray.stream().filter(item -> item[0] == calendar).findFirst();
return first.isPresent();
}
/**
* 字符串转时间戳
* @param date yyyyMMdd
* @return long 时间戳
*/
private long stringToCalendar(String date) {
Calendar instance = Calendar.getInstance();
instance.clear();
instance.set(Integer.parseInt(date.substring(0,4)),Integer.parseInt(date.substring(4,6)) - 1,Integer.parseInt(date.substring(6,8)), 0, 0, 0);
return instance.getTimeInMillis();
}
}
bootstrap.yml
account:
constant:
trading:
holidays: 20210731-20210930,
workdays: 20210727
使用
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@Slf4j
public class TradingTest {
@Autowired
private TradingDayUtil tradingDayUtil;
@Test
public void test1(){
Calendar instance = Calendar.getInstance();
instance.set(Calendar.DAY_OF_MONTH, 23);
log.info("" + tradingDayUtil.getT1(instance.getTime()));
}
}
启动测试
2021-07-21 14:22:34.872 INFO: 初始化tradingDayUtil
2021-07-21 14:22:34.873 INFO: 初始化tradingDayProperties
2021-07-21 14:22:34.878 INFO: 节假日参数处理完成
2021-07-21 14:22:41.726 INFO: Mon Jul 26 00:00:00 GMT+08:00 2021
注解说明
@EnableConfigurationProperties:启用对{@ConfigurationProperties}注释bean的支持。
@ConfigurationProperties:外部化配置的注释。 将其添加到类定义或
{ @Configuration}类中的{@Bean}方法