package com.nq.utils; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.concurrent.ConcurrentHashMap; /** * 交易日判断:优先走 HolidayUtil 接口,失败时回退 MarketUtils 硬编码列表。 */ public final class TradingDayUtil { private static final DateTimeFormatter YMD = DateTimeFormatter.ofPattern("yyyyMMdd"); private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); private TradingDayUtil() { } /** true=休市(周末或法定节假日) */ public static boolean isMarketClosed(LocalDate date) { if (date == null) { return false; } if (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY) { return true; } String key = date.toString(); return CACHE.computeIfAbsent(key, TradingDayUtil::resolveClosedOnApi); } /** 是否开启「节假日休市」(含落在工作日的法定假日本身) */ public static boolean isHolidayRestrictionEnabled(com.nq.pojo.SiteProduct siteProduct) { return siteProduct != null && Boolean.TRUE.equals(siteProduct.getHolidayDisplay()); } /** 开启节假日休市且今日为周末或法定假日本身时,禁止交易/出金等 */ public static boolean shouldBlockTradingToday(com.nq.pojo.SiteProduct siteProduct) { return isHolidayRestrictionEnabled(siteProduct) && isMarketClosed(LocalDate.now()); } /** 是否为 A 股交易日(非周末且非法定假日本身) */ public static boolean isTradingDay(LocalDate date) { return date != null && !isMarketClosed(date); } /** * @deprecated 递延费计费请使用 {@link StayFeeUtil} */ @Deprecated public static boolean isStayFeeChargeableDay(LocalDate date, boolean respectHoliday) { if (respectHoliday) { return isTradingDay(date); } return true; } private static boolean resolveClosedOnApi(String isoDate) { LocalDate date = LocalDate.parse(isoDate); try { String result = HolidayUtil.request(date.format(YMD)); if ("1".equals(result) || "2".equals(result)) { return true; } if ("0".equals(result)) { return false; } } catch (Exception ignored) { // 接口异常时回退本地节假日表 } return MarketUtils.isMarketClosed(date); } }