ipo
zyy3
2026-01-06 97f6fdc09138a2346b61ccc4c716e87ab58e590f
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package com.yami.trading.service;
 
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;
 
/**
 * 美股交易日统计工具(适配java.util.Date)
 */
public class UsStockTradingDayCalculator {
    // 美股纽约时区
    private static final ZoneId NEW_YORK_ZONE = ZoneId.of("America/New_York");
    // UTC时区(Date转ZonedDateTime的基准)
    private static final ZoneId UTC_ZONE = ZoneId.of("UTC");
 
    // ==================== 基础版:仅排除周末 ====================
    /**
     * 计算两个Date之间的美股交易日天数(仅排除周六/周日)
     * @param startDate 开始日期(java.util.Date)
     * @param endDate 结束日期(java.util.Date)
     * @return 美股交易日天数
     */
    public static int countUsStockTradingDays(Date startDate, Date endDate) {
        // 1. 参数校验
        if (startDate == null || endDate == null) {
            throw new IllegalArgumentException("startDate error");
        }
        if (startDate.after(endDate)) {
            throw new IllegalArgumentException("endDate error");
        }
 
        // 2. 将Date转换为纽约时区的LocalDate(核心:按纽约时间算日期)
        LocalDate startLocalDate = convertDateToNyLocalDate(startDate);
        LocalDate endLocalDate = convertDateToNyLocalDate(endDate);
 
        // 3. 遍历日期并统计交易日(非周六/周日)
        int tradingDays = 0;
        LocalDate currentDate = startLocalDate;
        while (!currentDate.isAfter(endLocalDate)) {
            DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
            // 非周六、非周日即为交易日
            if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
                tradingDays++;
            }
            currentDate = currentDate.plusDays(1);
        }
        return tradingDays;
    }
 
    // ==================== 进阶版:排除周末+美股法定节假日 ====================
    /**
     * 计算两个Date之间的美股交易日天数(排除周六/周日+美股法定节假日)
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 美股交易日天数
     */
    public static int countUsStockTradingDaysWithHolidays(Date startDate, Date endDate) {
        // 基础参数校验
        if (startDate == null || endDate == null) {
            throw new IllegalArgumentException("开始日期和结束日期不能为空");
        }
        if (startDate.after(endDate)) {
            throw new IllegalArgumentException("开始日期不能晚于结束日期");
        }
 
        // 转换为纽约时区的LocalDate
        LocalDate startLocalDate = convertDateToNyLocalDate(startDate);
        LocalDate endLocalDate = convertDateToNyLocalDate(endDate);
 
        // 预加载周期内涉及年份的美股节假日
        Set<LocalDate> holidays = new HashSet<>();
        for (int year = startLocalDate.getYear(); year <= endLocalDate.getYear(); year++) {
            holidays.addAll(getUsStockHolidays(year));
        }
 
        // 遍历统计(非周末+非节假日)
        int tradingDays = 0;
        LocalDate currentDate = startLocalDate;
        while (!currentDate.isAfter(endLocalDate)) {
            DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
            if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY
                    && !holidays.contains(currentDate)) {
                tradingDays++;
            }
            currentDate = currentDate.plusDays(1);
        }
        return tradingDays;
    }
 
    // ==================== 工具方法:Date转纽约时区LocalDate ====================
    /**
     * 将java.util.Date转换为纽约时区的LocalDate
     * @param date 待转换的Date
     * @return 纽约时区的LocalDate
     */
    private static LocalDate convertDateToNyLocalDate(Date date) {
        // Date -> Instant -> ZonedDateTime(UTC) -> ZonedDateTime(纽约) -> LocalDate
        Instant instant = date.toInstant();
        ZonedDateTime utcZoned = instant.atZone(UTC_ZONE);
        ZonedDateTime nyZoned = utcZoned.withZoneSameInstant(NEW_YORK_ZONE);
        return nyZoned.toLocalDate();
    }
 
    // ==================== 工具方法:获取指定年份的美股法定节假日 ====================
    /**
     * 获取指定年份的美股法定节假日(含调休规则)
     * @param year 年份
     * @return 节假日LocalDate集合
     */
    private static Set<LocalDate> getUsStockHolidays(int year) {
        Set<LocalDate> holidays = new HashSet<>();
 
        // 1. 新年(1月1日,周末则调休)
        LocalDate newYear = LocalDate.of(year, 1, 1);
        if (newYear.getDayOfWeek() == DayOfWeek.SATURDAY) {
            newYear = newYear.minusDays(1);
        } else if (newYear.getDayOfWeek() == DayOfWeek.SUNDAY) {
            newYear = newYear.plusDays(1);
        }
        holidays.add(newYear);
 
        // 2. 马丁·路德·金日(1月第三个周一)
        LocalDate mlkDay = LocalDate.of(year, 1, 1);
        while (mlkDay.getDayOfWeek() != DayOfWeek.MONDAY) {
            mlkDay = mlkDay.plusDays(1);
        }
        mlkDay = mlkDay.plusWeeks(2);
        holidays.add(mlkDay);
 
        // 3. 总统日(2月第三个周一)
        LocalDate presidentsDay = LocalDate.of(year, 2, 1);
        while (presidentsDay.getDayOfWeek() != DayOfWeek.MONDAY) {
            presidentsDay = presidentsDay.plusDays(1);
        }
        presidentsDay = presidentsDay.plusWeeks(2);
        holidays.add(presidentsDay);
 
        // 4. 阵亡将士纪念日(5月最后一个周一)
        LocalDate memorialDay = LocalDate.of(year, 5, 31);
        while (memorialDay.getDayOfWeek() != DayOfWeek.MONDAY) {
            memorialDay = memorialDay.minusDays(1);
        }
        holidays.add(memorialDay);
 
        // 5. 独立日(7月4日,周末则调休)
        LocalDate independenceDay = LocalDate.of(year, 7, 4);
        if (independenceDay.getDayOfWeek() == DayOfWeek.SATURDAY) {
            independenceDay = independenceDay.minusDays(1);
        } else if (independenceDay.getDayOfWeek() == DayOfWeek.SUNDAY) {
            independenceDay = independenceDay.plusDays(1);
        }
        holidays.add(independenceDay);
 
        // 6. 劳工节(9月第一个周一)
        LocalDate laborDay = LocalDate.of(year, 9, 1);
        while (laborDay.getDayOfWeek() != DayOfWeek.MONDAY) {
            laborDay = laborDay.plusDays(1);
        }
        holidays.add(laborDay);
 
        // 7. 感恩节(11月第四个周四)
        LocalDate thanksgiving = LocalDate.of(year, 11, 1);
        while (thanksgiving.getDayOfWeek() != DayOfWeek.THURSDAY) {
            thanksgiving = thanksgiving.plusDays(1);
        }
        thanksgiving = thanksgiving.plusWeeks(3);
        holidays.add(thanksgiving);
 
        // 8. 圣诞节(12月25日,周末则调休)
        LocalDate christmas = LocalDate.of(year, 12, 25);
        if (christmas.getDayOfWeek() == DayOfWeek.SATURDAY) {
            christmas = christmas.minusDays(1);
        } else if (christmas.getDayOfWeek() == DayOfWeek.SUNDAY) {
            christmas = christmas.plusDays(1);
        }
        holidays.add(christmas);
 
        return holidays;
    }
 
    // ==================== 测试示例 ====================
    public static void main(String[] args) {
        // 测试:2025-12-22(周一) ~ 2025-12-28(周日)
        Calendar cal1 = Calendar.getInstance();
        cal1.set(2025, Calendar.DECEMBER, 22);
        Date start = cal1.getTime();
 
        Calendar cal2 = Calendar.getInstance();
        cal2.set(2025, Calendar.DECEMBER, 28);
        Date end = cal2.getTime();
 
        // 基础版:仅排除周末,共5天(22-26日)
        int basicDays = countUsStockTradingDays(start, end);
        // 进阶版:若2025-12-25是圣诞节(周四),则排除,共4天
        int advancedDays = countUsStockTradingDaysWithHolidays(start, end);
 
        System.out.println("基础版(仅排周末)交易日数:" + basicDays);  // 输出:5
        System.out.println("进阶版(排周末+节假日)交易日数:" + advancedDays);  // 输出:4
    }
}