staran 1.0.6__py3-none-any.whl → 1.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Staran Date 模块增强功能演示
6
+ ==========================
7
+
8
+ 展示v1.0.7版本的所有新增和优化功能。
9
+ """
10
+
11
+ import sys
12
+ import os
13
+ import json
14
+
15
+ # 添加项目根目录到路径
16
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
17
+
18
+ from staran.date import Date
19
+
20
+
21
+ def enhanced_holidays_demo():
22
+ """增强的节假日功能演示"""
23
+ print("🎊 增强的节假日功能")
24
+ print("=" * 40)
25
+
26
+ # 中国节假日
27
+ print("中国节假日:")
28
+ cn_dates = ['20250101', '20250501', '20251001', '20250405']
29
+ for date_str in cn_dates:
30
+ date = Date(date_str)
31
+ is_holiday = date.is_holiday('CN')
32
+ status = "✅ 节假日" if is_holiday else "❌ 工作日"
33
+ print(f" {date.format_chinese()}: {status}")
34
+
35
+ # 美国节假日
36
+ print("\n美国节假日:")
37
+ us_dates = ['20250101', '20250704', '20251225', '20251127']
38
+ for date_str in us_dates:
39
+ date = Date(date_str)
40
+ is_holiday = date.is_holiday('US')
41
+ status = "✅ 节假日" if is_holiday else "❌ 工作日"
42
+ print(f" {date.format_iso()}: {status}")
43
+
44
+ print()
45
+
46
+
47
+ def batch_processing_demo():
48
+ """批量处理功能演示"""
49
+ print("⚡ 批量处理功能")
50
+ print("=" * 40)
51
+
52
+ # 批量创建
53
+ date_strings = ['20250101', '20250201', '20250301', '20250401']
54
+ dates = Date.batch_create(date_strings)
55
+ print("批量创建结果:")
56
+ for i, date in enumerate(dates):
57
+ print(f" {date_strings[i]} -> {date}")
58
+
59
+ # 批量格式化
60
+ print("\n批量格式化:")
61
+ iso_formats = Date.batch_format(dates, 'iso')
62
+ chinese_formats = Date.batch_format(dates, 'chinese')
63
+
64
+ for i, date in enumerate(dates):
65
+ print(f" 原始: {date}")
66
+ print(f" ISO: {iso_formats[i]}")
67
+ print(f" 中文: {chinese_formats[i]}")
68
+ print()
69
+
70
+
71
+ def timezone_demo():
72
+ """时区支持演示"""
73
+ print("🌍 时区支持功能")
74
+ print("=" * 40)
75
+
76
+ date = Date('20250101')
77
+
78
+ # 不同时区的时间戳
79
+ utc_timestamp = date.to_timestamp(0) # UTC
80
+ beijing_timestamp = date.to_timestamp(8) # 北京时间 (UTC+8)
81
+ ny_timestamp = date.to_timestamp(-5) # 纽约时间 (UTC-5)
82
+
83
+ print("同一日期在不同时区的时间戳:")
84
+ print(f" UTC: {utc_timestamp}")
85
+ print(f" 北京时间: {beijing_timestamp}")
86
+ print(f" 纽约时间: {ny_timestamp}")
87
+
88
+ # 从时间戳创建日期
89
+ print("\n从时间戳创建日期:")
90
+ base_timestamp = 1735689600 # 2025-01-01 00:00:00 UTC
91
+ utc_date = Date.from_timestamp(base_timestamp, 0)
92
+ beijing_date = Date.from_timestamp(base_timestamp, 8)
93
+
94
+ print(f" UTC时间戳 -> {utc_date.format_iso()}")
95
+ print(f" +8小时偏移 -> {beijing_date.format_iso()}")
96
+ print()
97
+
98
+
99
+ def business_rules_demo():
100
+ """业务规则演示"""
101
+ print("📊 业务规则功能")
102
+ print("=" * 40)
103
+
104
+ date = Date('20250415') # 2025年4月15日
105
+
106
+ print(f"基准日期: {date.format_chinese()}")
107
+
108
+ # 各种业务规则
109
+ rules = [
110
+ ('month_end', '月末'),
111
+ ('quarter_end', '季度末'),
112
+ ('next_business_day', '下一个工作日'),
113
+ ('prev_business_day', '上一个工作日')
114
+ ]
115
+
116
+ for rule, description in rules:
117
+ try:
118
+ result = date.apply_business_rule(rule)
119
+ print(f" {description}: {result.format_chinese()}")
120
+ except ValueError as e:
121
+ print(f" {description}: {e}")
122
+
123
+ print()
124
+
125
+
126
+ def enhanced_json_demo():
127
+ """增强JSON功能演示"""
128
+ print("📄 增强JSON序列化")
129
+ print("=" * 40)
130
+
131
+ date = Date('20250415')
132
+
133
+ # 包含元数据的JSON
134
+ json_with_meta = date.to_json(include_metadata=True)
135
+ json_simple = date.to_json(include_metadata=False)
136
+
137
+ print("包含元数据的JSON:")
138
+ print(json.dumps(json.loads(json_with_meta), indent=2, ensure_ascii=False))
139
+
140
+ print("\n简单JSON:")
141
+ print(json.dumps(json.loads(json_simple), indent=2, ensure_ascii=False))
142
+
143
+ # 字典转换
144
+ dict_with_meta = date.to_dict(include_metadata=True)
145
+ print("\n包含元数据的字典:")
146
+ for key, value in dict_with_meta.items():
147
+ print(f" {key}: {value}")
148
+
149
+ print()
150
+
151
+
152
+ def date_ranges_demo():
153
+ """日期范围功能演示"""
154
+ print("📅 新增日期范围功能")
155
+ print("=" * 40)
156
+
157
+ # 工作日和周末
158
+ print("一周的工作日和周末:")
159
+ business_days = Date.business_days('20250407', '20250413') # 一周
160
+ weekends = Date.weekends('20250407', '20250413')
161
+
162
+ print(" 工作日:", [str(d) for d in business_days])
163
+ print(" 周末:", [str(d) for d in weekends])
164
+
165
+ # 月份范围
166
+ print("\n月份范围 (前3个月):")
167
+ months = Date.month_range('202501', 3)
168
+ for month in months:
169
+ print(f" {month} ({month.format_chinese()})")
170
+
171
+ # 季度日期
172
+ print("\n2025年季度划分:")
173
+ quarters = Date.quarter_dates(2025)
174
+ for q, (start, end) in quarters.items():
175
+ print(f" Q{q}: {start.format_compact()} - {end.format_compact()}")
176
+
177
+ print()
178
+
179
+
180
+ def validation_demo():
181
+ """验证功能演示"""
182
+ print("✅ 日期验证功能")
183
+ print("=" * 40)
184
+
185
+ test_strings = [
186
+ '20250415', # 有效
187
+ '20250230', # 无效 - 2月30日
188
+ '202504', # 有效
189
+ 'invalid', # 无效
190
+ '20251301', # 无效 - 13月
191
+ ]
192
+
193
+ print("日期字符串验证:")
194
+ for test_str in test_strings:
195
+ is_valid = Date.is_valid_date_string(test_str)
196
+ status = "✅ 有效" if is_valid else "❌ 无效"
197
+ print(f" '{test_str}': {status}")
198
+
199
+ print()
200
+
201
+
202
+ def main():
203
+ """主演示函数"""
204
+ print("✨ Staran Date 模块 v1.0.7 增强功能演示")
205
+ print("=" * 50)
206
+ print()
207
+
208
+ # 运行各个演示
209
+ enhanced_holidays_demo()
210
+ batch_processing_demo()
211
+ timezone_demo()
212
+ business_rules_demo()
213
+ enhanced_json_demo()
214
+ date_ranges_demo()
215
+ validation_demo()
216
+
217
+ print("🎉 演示完成!")
218
+ print("\n📝 总结:")
219
+ print(" • 增强的节假日支持 (多国节假日)")
220
+ print(" • 高效的批量处理功能")
221
+ print(" • 基础时区转换支持")
222
+ print(" • 灵活的业务规则引擎")
223
+ print(" • 增强的JSON序列化")
224
+ print(" • 丰富的日期范围生成")
225
+ print(" • 严格的数据验证")
226
+ print("\n更多功能请查阅API文档! 📚")
227
+
228
+
229
+ if __name__ == '__main__':
230
+ main()
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Date类增强功能测试
6
+ ================
7
+
8
+ 测试新增的优化和改进功能:
9
+ - 增强的节假日支持
10
+ - 批量处理方法
11
+ - 时区支持
12
+ - 业务规则
13
+ - 改进的JSON序列化
14
+ """
15
+
16
+ import unittest
17
+ import datetime
18
+ import sys
19
+ import os
20
+
21
+ # 添加项目根目录到路径
22
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..'))
23
+
24
+ from staran.date.core import Date
25
+
26
+
27
+ class TestEnhancedHolidays(unittest.TestCase):
28
+ """测试增强的节假日功能"""
29
+
30
+ def test_chinese_holidays(self):
31
+ """测试中国节假日"""
32
+ # 元旦
33
+ new_year = Date('20250101')
34
+ self.assertTrue(new_year.is_holiday('CN'))
35
+
36
+ # 劳动节
37
+ labor_day = Date('20250501')
38
+ self.assertTrue(labor_day.is_holiday('CN'))
39
+
40
+ # 国庆节
41
+ national_day = Date('20251001')
42
+ self.assertTrue(national_day.is_holiday('CN'))
43
+
44
+ # 普通日期
45
+ regular_day = Date('20250315')
46
+ self.assertFalse(regular_day.is_holiday('CN'))
47
+
48
+ def test_us_holidays(self):
49
+ """测试美国节假日"""
50
+ # 独立日
51
+ independence_day = Date('20250704')
52
+ self.assertTrue(independence_day.is_holiday('US'))
53
+
54
+ # 圣诞节
55
+ christmas = Date('20251225')
56
+ self.assertTrue(christmas.is_holiday('US'))
57
+
58
+ # 感恩节测试(11月第四个星期四)
59
+ thanksgiving_2025 = Date('20251127') # 2025年11月27日是第四个星期四
60
+ self.assertTrue(thanksgiving_2025.is_holiday('US'))
61
+
62
+ def test_japanese_holidays(self):
63
+ """测试日本节假日"""
64
+ # 元日
65
+ new_year = Date('20250101')
66
+ self.assertTrue(new_year.is_holiday('JP'))
67
+
68
+ # 建国記念の日
69
+ foundation_day = Date('20250211')
70
+ self.assertTrue(foundation_day.is_holiday('JP'))
71
+
72
+ # 文化の日
73
+ culture_day = Date('20251103')
74
+ self.assertTrue(culture_day.is_holiday('JP'))
75
+
76
+
77
+ class TestBatchProcessing(unittest.TestCase):
78
+ """测试批量处理功能"""
79
+
80
+ def test_batch_create(self):
81
+ """测试批量创建"""
82
+ date_strings = ['20250101', '20250202', '20250303']
83
+ dates = Date.batch_create(date_strings)
84
+
85
+ self.assertEqual(len(dates), 3)
86
+ self.assertEqual(str(dates[0]), '20250101')
87
+ self.assertEqual(str(dates[1]), '20250202')
88
+ self.assertEqual(str(dates[2]), '20250303')
89
+
90
+ def test_batch_format(self):
91
+ """测试批量格式化"""
92
+ dates = [Date('20250101'), Date('20250202'), Date('20250303')]
93
+
94
+ # ISO格式
95
+ iso_results = Date.batch_format(dates, 'iso')
96
+ self.assertEqual(iso_results, ['2025-01-01', '2025-02-02', '2025-03-03'])
97
+
98
+ # 中文格式
99
+ chinese_results = Date.batch_format(dates, 'chinese')
100
+ self.assertEqual(chinese_results, ['2025年01月01日', '2025年02月02日', '2025年03月03日'])
101
+
102
+ def test_batch_add_days(self):
103
+ """测试批量添加天数"""
104
+ dates = [Date('20250101'), Date('20250202')]
105
+ new_dates = Date.batch_add_days(dates, 10)
106
+
107
+ self.assertEqual(str(new_dates[0]), '20250111')
108
+ self.assertEqual(str(new_dates[1]), '20250212')
109
+
110
+
111
+ class TestTimezoneSupport(unittest.TestCase):
112
+ """测试时区支持"""
113
+
114
+ def test_timestamp_with_timezone(self):
115
+ """测试带时区的时间戳转换"""
116
+ date = Date('20250101')
117
+
118
+ # 默认时区
119
+ timestamp_default = date.to_timestamp()
120
+
121
+ # 东八区
122
+ timestamp_utc8 = date.to_timestamp(8)
123
+
124
+ # 时差应该是8小时
125
+ self.assertAlmostEqual(timestamp_default - timestamp_utc8, 8 * 3600, delta=1)
126
+
127
+ def test_from_timestamp_with_timezone(self):
128
+ """测试从带时区的时间戳创建"""
129
+ timestamp = 1735689600 # 2025-01-01 00:00:00 UTC
130
+
131
+ # UTC时间
132
+ date_utc = Date.from_timestamp(timestamp, 0)
133
+
134
+ # 东八区时间
135
+ date_utc8 = Date.from_timestamp(timestamp, 8)
136
+
137
+ # 应该相差一天或在边界情况下相同
138
+ self.assertTrue(abs((date_utc8.to_date_object() - date_utc.to_date_object()).days) <= 1)
139
+
140
+
141
+ class TestBusinessRules(unittest.TestCase):
142
+ """测试业务规则"""
143
+
144
+ def test_month_end_rule(self):
145
+ """测试月末规则"""
146
+ date = Date('20250415')
147
+ month_end = date.apply_business_rule('month_end')
148
+ self.assertEqual(str(month_end), '20250430')
149
+
150
+ def test_quarter_end_rule(self):
151
+ """测试季度末规则"""
152
+ date = Date('20250415')
153
+ quarter_end = date.apply_business_rule('quarter_end')
154
+ self.assertEqual(str(quarter_end), '20250630')
155
+
156
+ def test_next_business_day_rule(self):
157
+ """测试下一个工作日规则"""
158
+ # 周五
159
+ friday = Date('20250418') # 假设这是周五
160
+ next_business = friday.add_days(1).apply_business_rule('next_business_day')
161
+
162
+ # 应该跳过周末到周一
163
+ self.assertTrue(next_business.is_business_day())
164
+
165
+ def test_prev_business_day_rule(self):
166
+ """测试上一个工作日规则"""
167
+ # 周一
168
+ monday = Date('20250421') # 假设这是周一
169
+ prev_business = monday.subtract_days(1).apply_business_rule('prev_business_day')
170
+
171
+ # 应该跳过周末到周五
172
+ self.assertTrue(prev_business.is_business_day())
173
+
174
+
175
+ class TestEnhancedJSON(unittest.TestCase):
176
+ """测试增强的JSON功能"""
177
+
178
+ def test_json_with_metadata(self):
179
+ """测试包含元数据的JSON序列化"""
180
+ date = Date('20250415')
181
+ json_str = date.to_json(include_metadata=True)
182
+
183
+ import json
184
+ data = json.loads(json_str)
185
+
186
+ # 检查基本字段
187
+ self.assertEqual(data['year'], 2025)
188
+ self.assertEqual(data['month'], 4)
189
+ self.assertEqual(data['day'], 15)
190
+
191
+ # 检查元数据
192
+ self.assertIn('weekday', data)
193
+ self.assertIn('is_weekend', data)
194
+ self.assertIn('quarter', data)
195
+ self.assertIn('version', data)
196
+
197
+ def test_json_without_metadata(self):
198
+ """测试不包含元数据的JSON序列化"""
199
+ date = Date('20250415')
200
+ json_str = date.to_json(include_metadata=False)
201
+
202
+ import json
203
+ data = json.loads(json_str)
204
+
205
+ # 检查基本字段存在
206
+ required_fields = ['date', 'year', 'month', 'day']
207
+ for field in required_fields:
208
+ self.assertIn(field, data)
209
+
210
+ # 检查元数据不存在
211
+ metadata_fields = ['weekday', 'is_weekend', 'quarter', 'version']
212
+ for field in metadata_fields:
213
+ self.assertNotIn(field, data)
214
+
215
+ def test_dict_with_metadata(self):
216
+ """测试包含元数据的字典转换"""
217
+ date = Date('20250415')
218
+ data = date.to_dict(include_metadata=True)
219
+
220
+ # 检查基本字段
221
+ self.assertEqual(data['year'], 2025)
222
+ self.assertEqual(data['month'], 4)
223
+ self.assertEqual(data['day'], 15)
224
+
225
+ # 检查元数据
226
+ self.assertIn('weekday', data)
227
+ self.assertIn('is_weekend', data)
228
+ self.assertIn('quarter', data)
229
+ self.assertIn('iso_string', data)
230
+ self.assertIn('compact_string', data)
231
+
232
+
233
+ class TestNewDateRanges(unittest.TestCase):
234
+ """测试新的日期范围功能"""
235
+
236
+ def test_weekends_range(self):
237
+ """测试周末范围生成"""
238
+ weekends = Date.weekends('20250401', '20250407') # 一周
239
+
240
+ # 应该只包含周末日期
241
+ for date in weekends:
242
+ self.assertTrue(date.is_weekend())
243
+
244
+ def test_month_range(self):
245
+ """测试月份范围生成"""
246
+ months = Date.month_range('202501', 3)
247
+
248
+ self.assertEqual(len(months), 3)
249
+ # 注意:月份范围返回的是年月格式,保持输入格式
250
+ self.assertEqual(str(months[0]), '202501') # 2025年1月1日
251
+ self.assertEqual(str(months[1]), '202502') # 2025年2月1日
252
+ self.assertEqual(str(months[2]), '202503') # 2025年3月1日
253
+
254
+ def test_quarter_dates(self):
255
+ """测试季度日期生成"""
256
+ quarters = Date.quarter_dates(2025)
257
+
258
+ self.assertEqual(len(quarters), 4)
259
+
260
+ # 检查第一季度 - 季度日期使用ISO格式
261
+ q1_start, q1_end = quarters[1]
262
+ self.assertEqual(q1_start.format_compact(), '20250101')
263
+ self.assertEqual(q1_end.format_compact(), '20250331')
264
+
265
+ # 检查第四季度
266
+ q4_start, q4_end = quarters[4]
267
+ self.assertEqual(q4_start.format_compact(), '20251001')
268
+ self.assertEqual(q4_end.format_compact(), '20251231')
269
+
270
+
271
+ class TestDateValidation(unittest.TestCase):
272
+ """测试日期验证功能"""
273
+
274
+ def test_is_valid_date_string(self):
275
+ """测试日期字符串验证"""
276
+ # 有效日期
277
+ self.assertTrue(Date.is_valid_date_string('20250415'))
278
+ self.assertTrue(Date.is_valid_date_string('202504'))
279
+ self.assertTrue(Date.is_valid_date_string('2025'))
280
+
281
+ # 无效日期
282
+ self.assertFalse(Date.is_valid_date_string('20250230')) # 2月30日
283
+ self.assertFalse(Date.is_valid_date_string('invalid'))
284
+ self.assertFalse(Date.is_valid_date_string(''))
285
+
286
+ def test_year_boundary_warning(self):
287
+ """测试年份边界警告"""
288
+ # 这个测试检查是否会记录警告日志
289
+ # 在实际应用中,可能需要设置日志级别来捕获警告
290
+ extreme_year_date = Date('10000101') # 公元1000年
291
+ self.assertEqual(extreme_year_date.year, 1000)
292
+
293
+
294
+ if __name__ == '__main__':
295
+ unittest.main(verbosity=2)