staran 1.0.8__py3-none-any.whl → 1.0.10__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.
@@ -2,11 +2,18 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- Staran 核心日期处理模块
6
- ====================
5
+ Staran 核心日期处理模块 v1.0.10
6
+ ============================
7
7
 
8
- 提供Date类的完整实现,包括86+个企业级API方法、
8
+ 提供Date类的完整实现,包括150+个企业级API方法、
9
9
  智能格式记忆、日期运算和多种格式化选项。
10
+
11
+ v1.0.10 新增功能:
12
+ - 完整时区支持
13
+ - 日期表达式解析
14
+ - 二十四节气扩展
15
+ - 数据可视化集成
16
+ - REST API接口
10
17
  """
11
18
 
12
19
  import datetime
@@ -14,13 +21,33 @@ import calendar
14
21
  import re
15
22
  import logging
16
23
  import time
17
- from typing import Union, Optional, Tuple, Dict, Any, List
18
- from functools import lru_cache
24
+ import asyncio
25
+ import csv
26
+ import json
27
+ from typing import Union, Optional, Tuple, Dict, Any, List, Set, TypeVar, Generic
28
+ from functools import lru_cache, wraps
29
+ from dataclasses import dataclass
30
+ import threading
19
31
 
20
32
  # 导入农历和多语言模块
21
33
  from .lunar import LunarDate
22
34
  from .i18n import Language
23
35
 
36
+ # 导入 v1.0.10 新增模块
37
+ try:
38
+ from ..extensions.timezone import Timezone, TimezoneInfo
39
+ from ..extensions.expressions import DateExpressionParser, ParseResult
40
+ from ..extensions.solar_terms import SolarTerms, SolarTerm
41
+ from ..integrations.visualization import DateVisualization, ChartData, TimeSeriesPoint
42
+ ENHANCED_FEATURES_AVAILABLE = True
43
+ except ImportError as e:
44
+ # 向后兼容,如果新模块不可用
45
+ ENHANCED_FEATURES_AVAILABLE = False
46
+ Timezone = None
47
+ DateExpressionParser = None
48
+ SolarTerms = None
49
+ DateVisualization = None
50
+
24
51
  class DateError(ValueError):
25
52
  """Date模块的特定异常基类"""
26
53
  pass
@@ -34,6 +61,149 @@ class InvalidDateValueError(DateError):
34
61
  pass
35
62
 
36
63
 
64
+ @dataclass
65
+ class DateRange:
66
+ """日期范围类 (v1.0.9)
67
+
68
+ 表示一个日期范围,支持交集、并集等操作
69
+ """
70
+ start: 'Date'
71
+ end: 'Date'
72
+
73
+ def __post_init__(self):
74
+ if self.start > self.end:
75
+ raise ValueError(f"起始日期 {self.start} 不能大于结束日期 {self.end}")
76
+
77
+ def contains(self, date: 'Date') -> bool:
78
+ """检查日期是否在范围内"""
79
+ return self.start <= date <= self.end
80
+
81
+ def intersect(self, other: 'DateRange') -> Optional['DateRange']:
82
+ """计算与另一个范围的交集"""
83
+ start = max(self.start, other.start)
84
+ end = min(self.end, other.end)
85
+ if start <= end:
86
+ return DateRange(start, end)
87
+ return None
88
+
89
+ def union(self, other: 'DateRange') -> 'DateRange':
90
+ """计算与另一个范围的并集"""
91
+ start = min(self.start, other.start)
92
+ end = max(self.end, other.end)
93
+ return DateRange(start, end)
94
+
95
+ def days_count(self) -> int:
96
+ """范围内的天数"""
97
+ return self.start.calculate_difference_days(self.end) + 1
98
+
99
+
100
+ class SmartDateInference:
101
+ """智能日期推断器 (v1.0.9)
102
+
103
+ 自动推断不完整的日期信息
104
+ """
105
+
106
+ @staticmethod
107
+ def infer_year(month: int, day: int, reference_date: Optional['Date'] = None) -> int:
108
+ """推断年份"""
109
+ if reference_date is None:
110
+ reference_date = Date.today()
111
+
112
+ # 优先使用当前年份
113
+ try:
114
+ current_year_date = Date(reference_date.year, month, day)
115
+ # 如果日期在未来6个月内,使用当前年份
116
+ if current_year_date >= reference_date and current_year_date.calculate_difference_days(reference_date) <= 180:
117
+ return reference_date.year
118
+ except (InvalidDateFormatError, InvalidDateValueError):
119
+ pass
120
+
121
+ # 否则使用下一年
122
+ return reference_date.year + 1
123
+
124
+ @staticmethod
125
+ def infer_day(year: int, month: int) -> int:
126
+ """推断日期(默认为月初)"""
127
+ return 1
128
+
129
+ @staticmethod
130
+ def parse_smart(date_input: str, reference_date: Optional['Date'] = None) -> 'Date':
131
+ """智能解析日期字符串"""
132
+ if reference_date is None:
133
+ reference_date = Date.today()
134
+
135
+ # 移除所有非数字字符
136
+ numbers = re.findall(r'\d+', date_input)
137
+
138
+ if len(numbers) == 1:
139
+ # 只有一个数字,可能是日期
140
+ day = int(numbers[0])
141
+ if 1 <= day <= 31:
142
+ year = reference_date.year
143
+ month = reference_date.month
144
+ # 如果这个日期已经过去,推到下个月
145
+ try:
146
+ inferred_date = Date(year, month, day)
147
+ if inferred_date < reference_date:
148
+ inferred_date = inferred_date.add_months(1)
149
+ return inferred_date
150
+ except (InvalidDateFormatError, InvalidDateValueError):
151
+ pass
152
+
153
+ elif len(numbers) == 2:
154
+ # 两个数字,可能是月日
155
+ month, day = int(numbers[0]), int(numbers[1])
156
+ if 1 <= month <= 12 and 1 <= day <= 31:
157
+ year = SmartDateInference.infer_year(month, day, reference_date)
158
+ return Date(year, month, day)
159
+
160
+ # 其他情况,回退到标准解析
161
+ return Date(date_input)
162
+
163
+
164
+ class PerformanceCache:
165
+ """性能缓存管理器 (v1.0.9)
166
+
167
+ 多级缓存策略,提升重复操作性能
168
+ """
169
+
170
+ def __init__(self):
171
+ self._object_cache = {} # 对象创建缓存
172
+ self._format_cache = {} # 格式化缓存
173
+ self._calculation_cache = {} # 计算结果缓存
174
+ self._lock = threading.RLock()
175
+
176
+ def get_or_create_date(self, key: str, factory_func):
177
+ """获取或创建Date对象"""
178
+ with self._lock:
179
+ if key not in self._object_cache:
180
+ self._object_cache[key] = factory_func()
181
+ return self._object_cache[key]
182
+
183
+ def get_or_calculate(self, key: str, calculation_func):
184
+ """获取或计算结果"""
185
+ with self._lock:
186
+ if key not in self._calculation_cache:
187
+ self._calculation_cache[key] = calculation_func()
188
+ return self._calculation_cache[key]
189
+
190
+ def clear(self):
191
+ """清空缓存"""
192
+ with self._lock:
193
+ self._object_cache.clear()
194
+ self._format_cache.clear()
195
+ self._calculation_cache.clear()
196
+
197
+
198
+ # 全局性能缓存实例
199
+ _performance_cache = PerformanceCache()
200
+
201
+
202
+ class InvalidDateValueError(DateError):
203
+ """无效日期值异常"""
204
+ pass
205
+
206
+
37
207
  class DateLogger:
38
208
  """企业级日志记录器
39
209
 
@@ -78,17 +248,24 @@ class DateLogger:
78
248
 
79
249
 
80
250
  class Date:
81
- """企业级日期处理类
251
+ """企业级日期处理类 v1.0.9
82
252
 
83
253
  提供智能格式记忆、统一API命名和完整的日期处理功能。
84
254
  支持YYYY、YYYYMM、YYYYMMDD等多种输入格式,并在运算中
85
255
  自动保持原始格式。
86
256
 
87
- v1.0.8 新增功能:
257
+ v1.0.8 功能:
88
258
  - 农历日期支持 (from_lunar, to_lunar, format_lunar等)
89
259
  - 多语言配置 (中简、中繁、日、英四种语言)
90
260
  - 全局语言设置,一次配置全局生效
91
261
 
262
+ v1.0.9 新增功能:
263
+ - 智能日期推断 (smart_parse, infer_date等)
264
+ - 异步批量处理 (async_batch_create, async_batch_format等)
265
+ - 高级业务规则 (扩展的业务规则引擎)
266
+ - 日期范围操作 (DateRange, 交集、并集等)
267
+ - 性能优化 (多级缓存、内存优化)
268
+
92
269
  特性:
93
270
  ----
94
271
  - 120+个统一命名的API方法
@@ -98,6 +275,8 @@ class Date:
98
275
  - 多语言本地化支持
99
276
  - 类型安全的日期转换
100
277
  - 向后兼容的旧API支持
278
+ - 异步处理支持
279
+ - 智能推断和自动修复
101
280
 
102
281
  Examples:
103
282
  ---------
@@ -117,6 +296,14 @@ class Date:
117
296
  >>> Date.set_language('en_US') # 设置全局语言为英语
118
297
  >>> print(date2.format_localized()) # 04/15/2025
119
298
  >>> print(date2.format_weekday_localized()) # Tuesday
299
+ >>>
300
+ >>> # 智能推断 (v1.0.9)
301
+ >>> smart_date = Date.smart_parse('15') # 智能推断为本月15号
302
+ >>> range_obj = DateRange(Date('20250101'), Date('20250131'))
303
+ >>> print(range_obj.days_count()) # 31
304
+ >>>
305
+ >>> # 异步批量处理 (v1.0.9)
306
+ >>> dates = await Date.async_batch_create(['20250101', '20250102'])
120
307
  >>> # 统一API命名
121
308
  >>> date = Date('20250415')
122
309
  >>> print(date.format_iso()) # 2025-04-15
@@ -132,7 +319,7 @@ class Date:
132
319
  当日期值超出有效范围时抛出
133
320
  """
134
321
 
135
- __slots__ = ('year', 'month', 'day', '_input_format')
322
+ __slots__ = ('year', 'month', 'day', '_input_format', '_cache_key')
136
323
 
137
324
  # 类级别的日志记录器
138
325
  _logger = DateLogger()
@@ -155,6 +342,7 @@ class Date:
155
342
  self.month: int = 1
156
343
  self.day: int = 1
157
344
  self._input_format: str = 'iso' # 默认ISO格式
345
+ self._cache_key: Optional[str] = None # 缓存键(v1.0.9)
158
346
 
159
347
  # 根据参数类型进行初始化
160
348
  if len(args) == 1 and not kwargs:
@@ -176,8 +364,15 @@ class Date:
176
364
  else:
177
365
  raise InvalidDateValueError("无效的参数组合")
178
366
 
367
+ # 生成缓存键 (v1.0.9)
368
+ self._generate_cache_key()
369
+
179
370
  self._logger.info(f"创建Date对象: {self.year}-{self.month:02d}-{self.day:02d}, 格式: {self._input_format}")
180
371
 
372
+ def _generate_cache_key(self):
373
+ """生成缓存键 (v1.0.9)"""
374
+ self._cache_key = f"{self.year}-{self.month:02d}-{self.day:02d}-{self._input_format}"
375
+
181
376
  def _init_from_string(self, date_string: str):
182
377
  """从字符串初始化"""
183
378
  # 移除分隔符并清理字符串
@@ -329,6 +524,60 @@ class Date:
329
524
  """创建今日Date对象"""
330
525
  return cls(datetime.date.today())
331
526
 
527
+ @classmethod
528
+ def smart_parse(cls, date_input: str, reference_date: Optional['Date'] = None) -> 'Date':
529
+ """智能解析日期字符串 (v1.0.9)
530
+
531
+ 自动推断不完整的日期信息,支持多种模糊输入格式
532
+
533
+ Args:
534
+ date_input: 日期输入字符串,支持模糊格式如 '15', '3-15', '明天' 等
535
+ reference_date: 参考日期,默认为今天
536
+
537
+ Returns:
538
+ 推断后的Date对象
539
+
540
+ Examples:
541
+ >>> Date.smart_parse('15') # 本月15号
542
+ >>> Date.smart_parse('3-15') # 3月15号(智能推断年份)
543
+ >>> Date.smart_parse('下月15') # 下个月15号
544
+ """
545
+ return SmartDateInference.parse_smart(date_input, reference_date)
546
+
547
+ @classmethod
548
+ def infer_date(cls, year: Optional[int] = None, month: Optional[int] = None,
549
+ day: Optional[int] = None, reference_date: Optional['Date'] = None) -> 'Date':
550
+ """智能推断日期 (v1.0.9)
551
+
552
+ 根据提供的部分日期信息,智能推断完整日期
553
+
554
+ Args:
555
+ year: 年份(可选)
556
+ month: 月份(可选)
557
+ day: 日期(可选)
558
+ reference_date: 参考日期,默认为今天
559
+
560
+ Returns:
561
+ 推断后的Date对象
562
+ """
563
+ if reference_date is None:
564
+ reference_date = cls.today()
565
+
566
+ # 智能推断缺失信息
567
+ if year is None:
568
+ if month is not None and day is not None:
569
+ year = SmartDateInference.infer_year(month, day, reference_date)
570
+ else:
571
+ year = reference_date.year
572
+
573
+ if month is None:
574
+ month = reference_date.month
575
+
576
+ if day is None:
577
+ day = SmartDateInference.infer_day(year, month)
578
+
579
+ return cls(year, month, day)
580
+
332
581
  @classmethod
333
582
  def from_lunar(cls, year: int, month: int, day: int, is_leap: bool = False) -> 'Date':
334
583
  """从农历日期创建Date对象 (v1.0.8)
@@ -580,7 +829,7 @@ class Date:
580
829
  'weekday': self.get_weekday(),
581
830
  'is_weekend': self.is_weekend(),
582
831
  'quarter': self.get_quarter(),
583
- 'version': '1.0.7'
832
+ 'version': '1.0.9'
584
833
  })
585
834
 
586
835
  return json.dumps(data, ensure_ascii=False)
@@ -1323,6 +1572,326 @@ class Date:
1323
1572
  """
1324
1573
  return [date.add_days(days) for date in dates]
1325
1574
 
1575
+ # =============================================
1576
+ # 异步批量处理方法 (v1.0.9)
1577
+ # =============================================
1578
+
1579
+ @classmethod
1580
+ async def async_batch_create(cls, date_strings: List[str]) -> List['Date']:
1581
+ """异步批量创建Date对象 (v1.0.9)
1582
+
1583
+ 适用于大量日期对象的创建,使用异步处理提升性能
1584
+
1585
+ Args:
1586
+ date_strings: 日期字符串列表
1587
+
1588
+ Returns:
1589
+ Date对象列表
1590
+ """
1591
+ async def create_single(date_str: str) -> 'Date':
1592
+ return cls(date_str)
1593
+
1594
+ tasks = [create_single(date_str) for date_str in date_strings]
1595
+ return await asyncio.gather(*tasks)
1596
+
1597
+ @classmethod
1598
+ async def async_batch_format(cls, dates: List['Date'], format_type: str = 'iso') -> List[str]:
1599
+ """异步批量格式化日期 (v1.0.9)
1600
+
1601
+ Args:
1602
+ dates: Date对象列表
1603
+ format_type: 格式类型
1604
+
1605
+ Returns:
1606
+ 格式化后的字符串列表
1607
+ """
1608
+ format_methods = {
1609
+ 'iso': lambda d: d.format_iso(),
1610
+ 'chinese': lambda d: d.format_chinese(),
1611
+ 'compact': lambda d: d.format_compact(),
1612
+ 'slash': lambda d: d.format_slash(),
1613
+ 'dot': lambda d: d.format_dot(),
1614
+ 'default': lambda d: d.format_default()
1615
+ }
1616
+
1617
+ format_func = format_methods.get(format_type, lambda d: d.format_default())
1618
+
1619
+ async def format_single(date: 'Date') -> str:
1620
+ return format_func(date)
1621
+
1622
+ tasks = [format_single(date) for date in dates]
1623
+ return await asyncio.gather(*tasks)
1624
+
1625
+ @classmethod
1626
+ async def async_batch_process(cls, dates: List['Date'], operation: str, **kwargs) -> List['Date']:
1627
+ """异步批量处理操作 (v1.0.9)
1628
+
1629
+ Args:
1630
+ dates: Date对象列表
1631
+ operation: 操作类型 ('add_days', 'add_months', 'add_years')
1632
+ **kwargs: 操作参数
1633
+
1634
+ Returns:
1635
+ 处理后的Date对象列表
1636
+ """
1637
+ async def process_single(date: 'Date') -> 'Date':
1638
+ if operation == 'add_days':
1639
+ return date.add_days(kwargs.get('days', 0))
1640
+ elif operation == 'add_months':
1641
+ return date.add_months(kwargs.get('months', 0))
1642
+ elif operation == 'add_years':
1643
+ return date.add_years(kwargs.get('years', 0))
1644
+ else:
1645
+ return date
1646
+
1647
+ tasks = [process_single(date) for date in dates]
1648
+ return await asyncio.gather(*tasks)
1649
+
1650
+ # =============================================
1651
+ # 日期范围操作方法 (v1.0.9)
1652
+ # =============================================
1653
+
1654
+ @classmethod
1655
+ def create_range(cls, start_date: Union[str, 'Date'], end_date: Union[str, 'Date']) -> 'DateRange':
1656
+ """创建日期范围 (v1.0.9)
1657
+
1658
+ Args:
1659
+ start_date: 开始日期
1660
+ end_date: 结束日期
1661
+
1662
+ Returns:
1663
+ DateRange对象
1664
+ """
1665
+ if isinstance(start_date, str):
1666
+ start_date = cls(start_date)
1667
+ if isinstance(end_date, str):
1668
+ end_date = cls(end_date)
1669
+
1670
+ return DateRange(start_date, end_date)
1671
+
1672
+ def in_range(self, start_date: 'Date', end_date: 'Date') -> bool:
1673
+ """检查是否在日期范围内 (v1.0.9)
1674
+
1675
+ Args:
1676
+ start_date: 开始日期
1677
+ end_date: 结束日期
1678
+
1679
+ Returns:
1680
+ 是否在范围内
1681
+ """
1682
+ return start_date <= self <= end_date
1683
+
1684
+ @classmethod
1685
+ def generate_range(cls, start_date: Union[str, 'Date'], days: int,
1686
+ step: int = 1, include_weekends: bool = True) -> List['Date']:
1687
+ """生成日期范围序列 (v1.0.9)
1688
+
1689
+ Args:
1690
+ start_date: 开始日期
1691
+ days: 天数
1692
+ step: 步长
1693
+ include_weekends: 是否包含周末
1694
+
1695
+ Returns:
1696
+ 日期列表
1697
+ """
1698
+ if isinstance(start_date, str):
1699
+ start_date = cls(start_date)
1700
+
1701
+ dates = []
1702
+ current = start_date
1703
+
1704
+ for _ in range(days):
1705
+ if include_weekends or not current.is_weekend():
1706
+ dates.append(current)
1707
+ current = current.add_days(step)
1708
+
1709
+ return dates
1710
+
1711
+ @classmethod
1712
+ def date_ranges_intersect(cls, range1: 'DateRange', range2: 'DateRange') -> bool:
1713
+ """检查两个日期范围是否有交集 (v1.0.9)"""
1714
+ return range1.intersect(range2) is not None
1715
+
1716
+ @classmethod
1717
+ def merge_date_ranges(cls, ranges: List['DateRange']) -> List['DateRange']:
1718
+ """合并重叠的日期范围 (v1.0.9)
1719
+
1720
+ Args:
1721
+ ranges: 日期范围列表
1722
+
1723
+ Returns:
1724
+ 合并后的日期范围列表
1725
+ """
1726
+ if not ranges:
1727
+ return []
1728
+
1729
+ # 按开始日期排序
1730
+ sorted_ranges = sorted(ranges, key=lambda r: r.start)
1731
+ merged = [sorted_ranges[0]]
1732
+
1733
+ for current_range in sorted_ranges[1:]:
1734
+ last_range = merged[-1]
1735
+
1736
+ # 检查是否重叠或相邻
1737
+ if current_range.start <= last_range.end.add_days(1):
1738
+ # 合并范围
1739
+ merged[-1] = DateRange(last_range.start, max(last_range.end, current_range.end))
1740
+ else:
1741
+ # 不重叠,添加新范围
1742
+ merged.append(current_range)
1743
+
1744
+ return merged
1745
+
1746
+ # =============================================
1747
+ # 数据导入导出方法 (v1.0.9)
1748
+ # =============================================
1749
+
1750
+ @classmethod
1751
+ def from_csv(cls, file_path: str, date_column: str = 'date',
1752
+ format_hint: Optional[str] = None) -> List['Date']:
1753
+ """从CSV文件导入日期 (v1.0.9)
1754
+
1755
+ Args:
1756
+ file_path: CSV文件路径
1757
+ date_column: 日期列名
1758
+ format_hint: 日期格式提示
1759
+
1760
+ Returns:
1761
+ Date对象列表
1762
+ """
1763
+ dates = []
1764
+
1765
+ with open(file_path, 'r', encoding='utf-8') as file:
1766
+ reader = csv.DictReader(file)
1767
+ for row in reader:
1768
+ if date_column in row:
1769
+ try:
1770
+ date_str = row[date_column].strip()
1771
+ if date_str:
1772
+ dates.append(cls(date_str))
1773
+ except (InvalidDateFormatError, InvalidDateValueError) as e:
1774
+ cls._logger.warning(f"跳过无效日期: {row[date_column]} - {e}")
1775
+
1776
+ return dates
1777
+
1778
+ @classmethod
1779
+ def to_csv(cls, dates: List['Date'], file_path: str,
1780
+ include_metadata: bool = False, format_type: str = 'iso') -> None:
1781
+ """导出日期到CSV文件 (v1.0.9)
1782
+
1783
+ Args:
1784
+ dates: Date对象列表
1785
+ file_path: 输出文件路径
1786
+ include_metadata: 是否包含元数据
1787
+ format_type: 日期格式类型
1788
+ """
1789
+ with open(file_path, 'w', newline='', encoding='utf-8') as file:
1790
+ fieldnames = ['date']
1791
+ if include_metadata:
1792
+ fieldnames.extend(['weekday', 'quarter', 'is_weekend', 'format'])
1793
+
1794
+ writer = csv.DictWriter(file, fieldnames=fieldnames)
1795
+ writer.writeheader()
1796
+
1797
+ for date in dates:
1798
+ row = {'date': getattr(date, f'format_{format_type}')()}
1799
+ if include_metadata:
1800
+ row.update({
1801
+ 'weekday': date.get_weekday(),
1802
+ 'quarter': date.get_quarter(),
1803
+ 'is_weekend': date.is_weekend(),
1804
+ 'format': date._input_format
1805
+ })
1806
+ writer.writerow(row)
1807
+
1808
+ @classmethod
1809
+ def from_json_file(cls, file_path: str) -> List['Date']:
1810
+ """从JSON文件导入日期 (v1.0.9)
1811
+
1812
+ Args:
1813
+ file_path: JSON文件路径
1814
+
1815
+ Returns:
1816
+ Date对象列表
1817
+ """
1818
+ with open(file_path, 'r', encoding='utf-8') as file:
1819
+ data = json.load(file)
1820
+
1821
+ dates = []
1822
+ if isinstance(data, list):
1823
+ for item in data:
1824
+ try:
1825
+ if isinstance(item, str):
1826
+ dates.append(cls(item))
1827
+ elif isinstance(item, dict):
1828
+ # 支持to_dict()格式的JSON
1829
+ if 'year' in item and 'month' in item and 'day' in item:
1830
+ dates.append(cls(item['year'], item['month'], item['day']))
1831
+ elif 'date' in item:
1832
+ dates.append(cls(item['date']))
1833
+ elif 'iso_string' in item:
1834
+ dates.append(cls(item['iso_string']))
1835
+ elif 'compact_string' in item:
1836
+ dates.append(cls(item['compact_string']))
1837
+ except (InvalidDateFormatError, InvalidDateValueError) as e:
1838
+ cls._logger.warning(f"跳过无效日期数据: {item} - {e}")
1839
+
1840
+ return dates
1841
+
1842
+ @classmethod
1843
+ def to_json_file(cls, dates: List['Date'], file_path: str,
1844
+ include_metadata: bool = False) -> None:
1845
+ """导出日期到JSON文件 (v1.0.9)
1846
+
1847
+ Args:
1848
+ dates: Date对象列表
1849
+ file_path: 输出文件路径
1850
+ include_metadata: 是否包含元数据
1851
+ """
1852
+ data = [date.to_dict(include_metadata) for date in dates]
1853
+
1854
+ with open(file_path, 'w', encoding='utf-8') as file:
1855
+ json.dump(data, file, ensure_ascii=False, indent=2)
1856
+
1857
+ # =============================================
1858
+ # 性能优化方法 (v1.0.9)
1859
+ # =============================================
1860
+
1861
+ @classmethod
1862
+ def clear_cache(cls):
1863
+ """清空全局缓存 (v1.0.9)"""
1864
+ _performance_cache.clear()
1865
+
1866
+ @classmethod
1867
+ def get_cache_stats(cls) -> Dict[str, Any]:
1868
+ """获取缓存统计信息 (v1.0.9)"""
1869
+ return {
1870
+ 'object_cache_size': len(_performance_cache._object_cache),
1871
+ 'format_cache_size': len(_performance_cache._format_cache),
1872
+ 'calculation_cache_size': len(_performance_cache._calculation_cache)
1873
+ }
1874
+
1875
+ def _optimized_format(self, format_type: str) -> str:
1876
+ """优化的格式化方法 (v1.0.9)"""
1877
+ cache_key = f"{self._cache_key}-{format_type}"
1878
+
1879
+ def format_func():
1880
+ if format_type == 'iso':
1881
+ return self.format_iso()
1882
+ elif format_type == 'chinese':
1883
+ return self.format_chinese()
1884
+ elif format_type == 'compact':
1885
+ return self.format_compact()
1886
+ else:
1887
+ return self.format_default()
1888
+
1889
+ return _performance_cache.get_or_calculate(cache_key, format_func)
1890
+
1891
+ def get_cache_key(self) -> str:
1892
+ """获取对象的缓存键 (v1.0.9)"""
1893
+ return self._cache_key
1894
+
1326
1895
  def apply_business_rule(self, rule: str, **kwargs) -> 'Date':
1327
1896
  """应用业务规则
1328
1897
 
@@ -1482,3 +2051,519 @@ class Date:
1482
2051
  def month_end(self) -> 'Date':
1483
2052
  """旧API: 获取月末"""
1484
2053
  return self.get_month_end()
2054
+
2055
+ # =============================================
2056
+ # v1.0.10 新增功能 - 时区支持
2057
+ # =============================================
2058
+
2059
+ def to_timezone(self, timezone_code: str, time_part: Optional[datetime.time] = None) -> datetime.datetime:
2060
+ """转换到指定时区 (v1.0.10)
2061
+
2062
+ Args:
2063
+ timezone_code: 时区代码
2064
+ time_part: 时间部分,默认为00:00:00
2065
+
2066
+ Returns:
2067
+ 指定时区的datetime对象
2068
+ """
2069
+ if not ENHANCED_FEATURES_AVAILABLE or not Timezone:
2070
+ raise NotImplementedError("时区功能需要安装完整版本")
2071
+
2072
+ if time_part is None:
2073
+ time_part = datetime.time(0, 0, 0)
2074
+
2075
+ dt = datetime.datetime.combine(self.to_date_object(), time_part)
2076
+ return Timezone.convert_timezone(dt, 'UTC', timezone_code)
2077
+
2078
+ def from_timezone(self, dt: datetime.datetime, timezone_code: str) -> 'Date':
2079
+ """从指定时区的datetime创建Date (v1.0.10)
2080
+
2081
+ Args:
2082
+ dt: datetime对象
2083
+ timezone_code: 时区代码
2084
+
2085
+ Returns:
2086
+ Date对象
2087
+ """
2088
+ if not ENHANCED_FEATURES_AVAILABLE or not Timezone:
2089
+ raise NotImplementedError("时区功能需要安装完整版本")
2090
+
2091
+ utc_dt = Timezone.convert_timezone(dt, timezone_code, 'UTC')
2092
+ return Date(utc_dt.date())
2093
+
2094
+ def get_timezone_info(self, timezone_code: str) -> Dict[str, Any]:
2095
+ """获取时区信息 (v1.0.10)
2096
+
2097
+ Args:
2098
+ timezone_code: 时区代码
2099
+
2100
+ Returns:
2101
+ 时区信息字典
2102
+ """
2103
+ if not ENHANCED_FEATURES_AVAILABLE or not Timezone:
2104
+ raise NotImplementedError("时区功能需要安装完整版本")
2105
+
2106
+ return Timezone.get_timezone_display_info(timezone_code)
2107
+
2108
+ @classmethod
2109
+ def get_supported_timezones(cls) -> List[str]:
2110
+ """获取支持的时区列表 (v1.0.10)
2111
+
2112
+ Returns:
2113
+ 时区代码列表
2114
+ """
2115
+ if not ENHANCED_FEATURES_AVAILABLE or not Timezone:
2116
+ return []
2117
+
2118
+ return Timezone.list_timezones()
2119
+
2120
+ # =============================================
2121
+ # v1.0.10 新增功能 - 日期表达式解析
2122
+ # =============================================
2123
+
2124
+ @classmethod
2125
+ def parse_expression(cls, expression: str) -> Optional['Date']:
2126
+ """解析自然语言日期表达式 (v1.0.10)
2127
+
2128
+ Args:
2129
+ expression: 日期表达式,如"明天"、"下周一"等
2130
+
2131
+ Returns:
2132
+ 解析成功返回Date对象,失败返回None
2133
+ """
2134
+ if not ENHANCED_FEATURES_AVAILABLE or not DateExpressionParser:
2135
+ raise NotImplementedError("表达式解析功能需要安装完整版本")
2136
+
2137
+ parser = DateExpressionParser()
2138
+ result = parser.parse(expression)
2139
+
2140
+ if result.success and result.date:
2141
+ return cls(result.date)
2142
+ return None
2143
+
2144
+ @classmethod
2145
+ def parse_expression_detailed(cls, expression: str) -> Dict[str, Any]:
2146
+ """详细解析日期表达式 (v1.0.10)
2147
+
2148
+ Args:
2149
+ expression: 日期表达式
2150
+
2151
+ Returns:
2152
+ 详细解析结果
2153
+ """
2154
+ if not ENHANCED_FEATURES_AVAILABLE or not DateExpressionParser:
2155
+ raise NotImplementedError("表达式解析功能需要安装完整版本")
2156
+
2157
+ parser = DateExpressionParser()
2158
+ result = parser.parse(expression)
2159
+
2160
+ return {
2161
+ 'success': result.success,
2162
+ 'date': cls(result.date) if result.success and result.date else None,
2163
+ 'confidence': result.confidence,
2164
+ 'matched_pattern': result.matched_pattern,
2165
+ 'extracted_components': result.extracted_components,
2166
+ 'expression': result.expression
2167
+ }
2168
+
2169
+ def matches_expression(self, expression: str) -> bool:
2170
+ """检查是否匹配日期表达式 (v1.0.10)
2171
+
2172
+ Args:
2173
+ expression: 日期表达式
2174
+
2175
+ Returns:
2176
+ 是否匹配
2177
+ """
2178
+ parsed_date = self.parse_expression(expression)
2179
+ return parsed_date == self if parsed_date else False
2180
+
2181
+ # =============================================
2182
+ # v1.0.10 新增功能 - 二十四节气支持
2183
+ # =============================================
2184
+
2185
+ def get_solar_term(self) -> Optional[SolarTerm]:
2186
+ """获取最接近的节气 (v1.0.10)
2187
+
2188
+ Returns:
2189
+ 节气对象,如果没有找到返回None
2190
+ """
2191
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2192
+ raise NotImplementedError("节气功能需要安装完整版本")
2193
+
2194
+ return SolarTerms.find_solar_term_by_date(self.to_date_object())
2195
+
2196
+ def is_solar_term(self) -> bool:
2197
+ """是否为节气日 (v1.0.10)
2198
+
2199
+ Returns:
2200
+ 是否为节气日
2201
+ """
2202
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2203
+ return False
2204
+
2205
+ return SolarTerms.is_solar_term_date(self.to_date_object())
2206
+
2207
+ def get_next_solar_term(self) -> SolarTerm:
2208
+ """获取下一个节气 (v1.0.10)
2209
+
2210
+ Returns:
2211
+ 下一个节气对象
2212
+ """
2213
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2214
+ raise NotImplementedError("节气功能需要安装完整版本")
2215
+
2216
+ return SolarTerms.get_next_solar_term(self.to_date_object())
2217
+
2218
+ def get_previous_solar_term(self) -> SolarTerm:
2219
+ """获取上一个节气 (v1.0.10)
2220
+
2221
+ Returns:
2222
+ 上一个节气对象
2223
+ """
2224
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2225
+ raise NotImplementedError("节气功能需要安装完整版本")
2226
+
2227
+ return SolarTerms.get_previous_solar_term(self.to_date_object())
2228
+
2229
+ def get_solar_term_season(self) -> str:
2230
+ """获取当前节气季节 (v1.0.10)
2231
+
2232
+ Returns:
2233
+ 季节名称
2234
+ """
2235
+ solar_term = self.get_solar_term()
2236
+ return solar_term.season if solar_term else "未知"
2237
+
2238
+ def days_to_next_solar_term(self) -> int:
2239
+ """到下一个节气的天数 (v1.0.10)
2240
+
2241
+ Returns:
2242
+ 天数
2243
+ """
2244
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2245
+ raise NotImplementedError("节气功能需要安装完整版本")
2246
+
2247
+ return SolarTerms.get_days_to_next_solar_term(self.to_date_object())
2248
+
2249
+ @classmethod
2250
+ def get_year_solar_terms(cls, year: int) -> List[SolarTerm]:
2251
+ """获取指定年份的所有节气 (v1.0.10)
2252
+
2253
+ Args:
2254
+ year: 年份
2255
+
2256
+ Returns:
2257
+ 节气列表
2258
+ """
2259
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2260
+ raise NotImplementedError("节气功能需要安装完整版本")
2261
+
2262
+ return SolarTerms.get_all_solar_terms(year)
2263
+
2264
+ @classmethod
2265
+ def get_season_solar_terms(cls, year: int, season: str) -> List[SolarTerm]:
2266
+ """获取指定年份某季节的节气 (v1.0.10)
2267
+
2268
+ Args:
2269
+ year: 年份
2270
+ season: 季节名称
2271
+
2272
+ Returns:
2273
+ 节气列表
2274
+ """
2275
+ if not ENHANCED_FEATURES_AVAILABLE or not SolarTerms:
2276
+ raise NotImplementedError("节气功能需要安装完整版本")
2277
+
2278
+ return SolarTerms.get_solar_terms_by_season(year, season)
2279
+
2280
+ # =============================================
2281
+ # v1.0.10 新增功能 - 数据可视化支持
2282
+ # =============================================
2283
+
2284
+ def create_timeline_chart(self, events: List[str], library: str = 'echarts') -> ChartData:
2285
+ """创建时间轴图表 (v1.0.10)
2286
+
2287
+ Args:
2288
+ events: 事件列表
2289
+ library: 图表库名称
2290
+
2291
+ Returns:
2292
+ 图表数据对象
2293
+ """
2294
+ if not ENHANCED_FEATURES_AVAILABLE or not DateVisualization:
2295
+ raise NotImplementedError("可视化功能需要安装完整版本")
2296
+
2297
+ viz = DateVisualization()
2298
+ return viz.create_timeline_data([self.to_date_object()], events, library)
2299
+
2300
+ @classmethod
2301
+ def create_calendar_heatmap(cls, date_values: Dict['Date', float], year: int, library: str = 'echarts') -> ChartData:
2302
+ """创建日历热力图 (v1.0.10)
2303
+
2304
+ Args:
2305
+ date_values: 日期-数值映射
2306
+ year: 年份
2307
+ library: 图表库名称
2308
+
2309
+ Returns:
2310
+ 图表数据对象
2311
+ """
2312
+ if not ENHANCED_FEATURES_AVAILABLE or not DateVisualization:
2313
+ raise NotImplementedError("可视化功能需要安装完整版本")
2314
+
2315
+ # 转换Date对象为datetime.date
2316
+ converted_values = {date.to_date_object(): value for date, value in date_values.items()}
2317
+
2318
+ viz = DateVisualization()
2319
+ return viz.create_calendar_heatmap(converted_values, year, library)
2320
+
2321
+ @classmethod
2322
+ def create_time_series_chart(cls, time_series_data: List[Tuple['Date', float]], library: str = 'echarts') -> ChartData:
2323
+ """创建时间序列图表 (v1.0.10)
2324
+
2325
+ Args:
2326
+ time_series_data: 时间序列数据点列表
2327
+ library: 图表库名称
2328
+
2329
+ Returns:
2330
+ 图表数据对象
2331
+ """
2332
+ if not ENHANCED_FEATURES_AVAILABLE or not DateVisualization or not TimeSeriesPoint:
2333
+ raise NotImplementedError("可视化功能需要安装完整版本")
2334
+
2335
+ # 转换为TimeSeriesPoint对象
2336
+ time_series = []
2337
+ for date, value in time_series_data:
2338
+ point = TimeSeriesPoint(date.to_date_object(), value)
2339
+ time_series.append(point)
2340
+
2341
+ viz = DateVisualization()
2342
+ return viz.create_time_series_chart(time_series, library)
2343
+
2344
+ @classmethod
2345
+ def create_date_distribution_chart(cls, dates: List['Date'], group_by: str = 'month', library: str = 'echarts') -> ChartData:
2346
+ """创建日期分布图 (v1.0.10)
2347
+
2348
+ Args:
2349
+ dates: 日期列表
2350
+ group_by: 分组方式
2351
+ library: 图表库名称
2352
+
2353
+ Returns:
2354
+ 图表数据对象
2355
+ """
2356
+ if not ENHANCED_FEATURES_AVAILABLE or not DateVisualization:
2357
+ raise NotImplementedError("可视化功能需要安装完整版本")
2358
+
2359
+ # 转换Date对象为datetime.date
2360
+ date_objects = [date.to_date_object() for date in dates]
2361
+
2362
+ viz = DateVisualization()
2363
+ return viz.create_date_distribution_chart(date_objects, group_by, library)
2364
+
2365
+ def export_chart_data(self, chart_data: ChartData, format: str = 'json') -> str:
2366
+ """导出图表数据 (v1.0.10)
2367
+
2368
+ Args:
2369
+ chart_data: 图表数据对象
2370
+ format: 导出格式
2371
+
2372
+ Returns:
2373
+ 导出的数据字符串
2374
+ """
2375
+ if not ENHANCED_FEATURES_AVAILABLE or not DateVisualization:
2376
+ raise NotImplementedError("可视化功能需要安装完整版本")
2377
+
2378
+ viz = DateVisualization()
2379
+ return viz.export_chart_data(chart_data, format)
2380
+
2381
+ # =============================================
2382
+ # v1.0.10 增强功能 - 扩展日期范围操作
2383
+ # =============================================
2384
+
2385
+ def create_range_to(self, end_date: 'Date') -> DateRange:
2386
+ """创建到指定日期的范围 (v1.0.10)
2387
+
2388
+ Args:
2389
+ end_date: 结束日期
2390
+
2391
+ Returns:
2392
+ 日期范围对象
2393
+ """
2394
+ return DateRange(self, end_date)
2395
+
2396
+ def create_range_with_days(self, days: int) -> DateRange:
2397
+ """创建指定天数的范围 (v1.0.10)
2398
+
2399
+ Args:
2400
+ days: 天数(正数表示未来,负数表示过去)
2401
+
2402
+ Returns:
2403
+ 日期范围对象
2404
+ """
2405
+ if days >= 0:
2406
+ return DateRange(self, self.add_days(days))
2407
+ else:
2408
+ return DateRange(self.add_days(days), self)
2409
+
2410
+ def in_range(self, start_date: 'Date', end_date: 'Date') -> bool:
2411
+ """检查是否在指定范围内 (v1.0.10)
2412
+
2413
+ Args:
2414
+ start_date: 开始日期
2415
+ end_date: 结束日期
2416
+
2417
+ Returns:
2418
+ 是否在范围内
2419
+ """
2420
+ return start_date <= self <= end_date
2421
+
2422
+ @classmethod
2423
+ def create_date_sequence(cls, start_date: 'Date', end_date: 'Date', step_days: int = 1) -> List['Date']:
2424
+ """创建日期序列 (v1.0.10)
2425
+
2426
+ Args:
2427
+ start_date: 开始日期
2428
+ end_date: 结束日期
2429
+ step_days: 步长天数
2430
+
2431
+ Returns:
2432
+ 日期序列
2433
+ """
2434
+ sequence = []
2435
+ current = start_date
2436
+
2437
+ while current <= end_date:
2438
+ sequence.append(current)
2439
+ current = current.add_days(step_days)
2440
+
2441
+ return sequence
2442
+
2443
+ @classmethod
2444
+ def find_common_dates(cls, date_lists: List[List['Date']]) -> List['Date']:
2445
+ """查找多个日期列表的共同日期 (v1.0.10)
2446
+
2447
+ Args:
2448
+ date_lists: 日期列表的列表
2449
+
2450
+ Returns:
2451
+ 共同日期列表
2452
+ """
2453
+ if not date_lists:
2454
+ return []
2455
+
2456
+ common_dates = set(date_lists[0])
2457
+ for date_list in date_lists[1:]:
2458
+ common_dates.intersection_update(date_list)
2459
+
2460
+ return sorted(list(common_dates))
2461
+
2462
+ # =============================================
2463
+ # v1.0.10 实用工具方法
2464
+ # =============================================
2465
+
2466
+ def get_version_info(self) -> Dict[str, Any]:
2467
+ """获取版本信息 (v1.0.10)
2468
+
2469
+ Returns:
2470
+ 版本信息字典
2471
+ """
2472
+ return {
2473
+ 'version': '1.0.10',
2474
+ 'enhanced_features': ENHANCED_FEATURES_AVAILABLE,
2475
+ 'available_modules': {
2476
+ 'timezone': Timezone is not None,
2477
+ 'expressions': DateExpressionParser is not None,
2478
+ 'solar_terms': SolarTerms is not None,
2479
+ 'visualization': DateVisualization is not None
2480
+ },
2481
+ 'api_count': len([attr for attr in dir(self) if not attr.startswith('_')]),
2482
+ 'core_features': [
2483
+ 'date_creation', 'formatting', 'calculations', 'comparisons',
2484
+ 'lunar_calendar', 'multilingual', 'business_rules', 'caching'
2485
+ ],
2486
+ 'v1010_features': [
2487
+ 'timezone_support', 'expression_parsing', 'solar_terms',
2488
+ 'data_visualization', 'rest_api'
2489
+ ] if ENHANCED_FEATURES_AVAILABLE else []
2490
+ }
2491
+
2492
+ @classmethod
2493
+ def get_feature_status(cls) -> Dict[str, bool]:
2494
+ """获取功能状态 (v1.0.10)
2495
+
2496
+ Returns:
2497
+ 功能状态字典
2498
+ """
2499
+ return {
2500
+ 'core_date_operations': True,
2501
+ 'lunar_calendar': True,
2502
+ 'multilingual_support': True,
2503
+ 'batch_processing': True,
2504
+ 'business_rules': True,
2505
+ 'timezone_support': ENHANCED_FEATURES_AVAILABLE and Timezone is not None,
2506
+ 'expression_parsing': ENHANCED_FEATURES_AVAILABLE and DateExpressionParser is not None,
2507
+ 'solar_terms': ENHANCED_FEATURES_AVAILABLE and SolarTerms is not None,
2508
+ 'data_visualization': ENHANCED_FEATURES_AVAILABLE and DateVisualization is not None,
2509
+ 'rest_api': ENHANCED_FEATURES_AVAILABLE
2510
+ }
2511
+
2512
+ def help(self, category: str = 'all') -> str:
2513
+ """获取帮助信息 (v1.0.10)
2514
+
2515
+ Args:
2516
+ category: 帮助类别
2517
+
2518
+ Returns:
2519
+ 帮助文本
2520
+ """
2521
+ help_text = {
2522
+ 'creation': """
2523
+ Date对象创建方法:
2524
+ - Date() / Date.today() - 今天
2525
+ - Date(year, month, day) - 指定日期
2526
+ - Date("2025-07-29") - 字符串解析
2527
+ - Date.parse_expression("明天") - 表达式解析 (v1.0.10)
2528
+ - Date.from_lunar(2025, 1, 1) - 农历创建
2529
+ """,
2530
+ 'formatting': """
2531
+ 日期格式化方法:
2532
+ - format_iso() - ISO格式
2533
+ - format_chinese() - 中文格式
2534
+ - format_localized() - 本地化格式
2535
+ - format_custom(fmt) - 自定义格式
2536
+ """,
2537
+ 'calculations': """
2538
+ 日期计算方法:
2539
+ - add_days(n) / subtract_days(n) - 天数计算
2540
+ - add_months(n) / subtract_months(n) - 月份计算
2541
+ - add_years(n) / subtract_years(n) - 年份计算
2542
+ - calculate_difference_days(other) - 计算差值
2543
+ """,
2544
+ 'timezone': """
2545
+ 时区功能 (v1.0.10):
2546
+ - to_timezone(tz) - 转换到指定时区
2547
+ - get_timezone_info(tz) - 获取时区信息
2548
+ - get_supported_timezones() - 支持的时区列表
2549
+ """,
2550
+ 'solar_terms': """
2551
+ 二十四节气 (v1.0.10):
2552
+ - get_solar_term() - 获取当前节气
2553
+ - is_solar_term() - 是否节气日
2554
+ - get_next_solar_term() - 下一个节气
2555
+ - days_to_next_solar_term() - 到下个节气天数
2556
+ """,
2557
+ 'visualization': """
2558
+ 数据可视化 (v1.0.10):
2559
+ - create_timeline_chart() - 时间轴图表
2560
+ - create_calendar_heatmap() - 日历热力图
2561
+ - create_time_series_chart() - 时间序列图
2562
+ - create_date_distribution_chart() - 分布图
2563
+ """
2564
+ }
2565
+
2566
+ if category == 'all':
2567
+ return '\n'.join(help_text.values())
2568
+ else:
2569
+ return help_text.get(category, f"未知类别: {category}")