1
zj
5 hours ago d615fc515fc52d6ed970c11d59a017e48de4be32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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<String, Boolean> 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);
    }
}