///|
/// timezone_impl.mbt — 运行时上层算法(chrono_tz-mbt MoonBit 移植)
/// 移植自仓颉 src/base/tz/timezone_impl.cj + moon-chrono_tz/tz/timezone_impl.mbt。
/// binary_search / TzError / TzOffset / LocalResult / TimeZone trait。
/// GapInfo 延迟到 S5(依赖 DateTime)。
///|
/// 时区操作错误类型(suberror 自动提升 Error)。
/// 分层策略(ADR-008):查无 → T?;非法输入 → raise TzError;不变量破坏 → abort。
pub(all) suberror TzError {
InvalidTzName(String)
InvalidDate(Int64, Int64, Int64)
InvalidTime(Int64, Int64, Int64)
InvalidDayOfYear(Int64, Int64, Int32)
InvalidTimestamp(Int64)
InvalidFormatString(String)
ParseError(String, Int32)
Rfc3339ParseError(String, Int32)
TzOffsetOutOfRange(Int32)
} derive(Debug)
///|
pub extend TzError with Debug::{to_repr}
///|
/// 二分查找,镜像 Rust `slice::binary_search_by` 语义。
/// Ok(idx) = 命中元素索引;Err(idx) = 插入点索引。
pub fn binary_search(
start : Int32,
end : Int32,
f : (Int32) -> @core.Ordering,
) -> Result[Int32, Int32] {
let mut s = start
let mut e = end
while s < e {
let mid = s + (e - s) / 2
match f(mid) {
@core.Ordering::Less => s = mid + 1
@core.Ordering::Greater => e = mid
@core.Ordering::Equal => return Ok(mid)
}
}
Err(s)
}
///|
/// 某 UTC 瞬时在某时区下的偏移,由时区与命中的 FixedTimespan 段组成。
pub struct TzOffset {
tz : Tz
span : @core.FixedTimespan
} derive(Eq, Debug)
///|
pub extend TzOffset with Eq::{not_equal, equal}
///|
pub extend TzOffset with Debug::{to_repr}
///|
/// 由时区与命中的 FixedTimespan 构造。
pub fn TzOffset::make(tz : Tz, offset : @core.FixedTimespan) -> TzOffset {
TzOffset::{ tz, span: offset, }
}
///|
/// 返回 IANA 时区 ID(如 `Europe/Paris`)。
pub fn TzOffset::tz_id(self : TzOffset) -> String {
self.tz.name()
}
///|
/// 返回偏移缩写(如 `CET`、`CEST`)。
pub fn TzOffset::abbreviation(self : TzOffset) -> String {
self.span.name
}
///|
/// 返回偏移秒数(如 CET = +3600)。
pub fn TzOffset::offset_sec(self : TzOffset) -> Int32 {
self.span.offset
}
///|
/// 返回偏移展示名(与 abbreviation 同源)。
pub fn TzOffset::offset(self : TzOffset) -> String {
self.abbreviation()
}
///|
/// 返回偏移缩写字符串(同 abbreviation)。
pub fn TzOffset::to_string(self : TzOffset) -> String {
self.abbreviation()
}
///|
/// 本地墙钟→UTC 解析的三分支结果,表达 DST 歧义与缺口。
pub enum LocalResult[T] {
Single(T)
Ambiguous(T, T)
None
}
///|
/// 若为 Single 则返回 Some(v),否则 None。
pub fn[T] LocalResult::single(self : LocalResult[T]) -> T? {
match self {
LocalResult::Single(v) => Some(v)
_ => None
}
}
///|
/// 取最早候选:Single 取其值,Ambiguous 取第一个,None 抛异常。
pub fn[T] LocalResult::earliest(self : LocalResult[T]) -> T {
match self {
LocalResult::Single(v) => v
LocalResult::Ambiguous(a, _) => a
LocalResult::None => abort("LocalResult.earliest on None")
}
}
///|
/// 取最晚候选:Single 取其值,Ambiguous 取第二个,None 抛异常。
pub fn[T] LocalResult::latest(self : LocalResult[T]) -> T {
match self {
LocalResult::Single(v) => v
LocalResult::Ambiguous(_, b) => b
LocalResult::None => abort("LocalResult.latest on None")
}
}
///|
/// 取唯一的 Single 值,Ambiguous 或 None 时抛异常。
pub fn[T] LocalResult::unwrap(self : LocalResult[T]) -> T {
match self {
LocalResult::Single(v) => v
_ => abort("LocalResult.unwrap on non-Single value")
}
}
///|
/// 判定是否为 Single。
pub fn[T] LocalResult::is_single(self : LocalResult[T]) -> Bool {
match self {
LocalResult::Single(_) => true
_ => false
}
}
///|
/// 判定是否为 None(DST 春进缺口)。
pub fn[T] LocalResult::is_none(self : LocalResult[T]) -> Bool {
match self {
LocalResult::None => true
_ => false
}
}
///|
/// 判定是否为 Ambiguous(DST 秋退重叠)。
pub fn[T] LocalResult::is_ambiguous(self : LocalResult[T]) -> Bool {
match self {
LocalResult::Ambiguous(_, _) => true
_ => false
}
}
///|
/// 时区等价接口(最小子集)。
/// S5 中 Tz 实现此 trait:`pub extend Tz with TimeZone::{offset_from_utc_date_time, offset_from_local_date_time}`。
pub(open) trait TimeZone {
fn offset_from_utc_date_time(Self, NaiveDateTime) -> TzOffset
fn offset_from_local_date_time(Self, NaiveDateTime) -> LocalResult[TzOffset]
}