///|
/// tz_rfc2822.mbt — RFC2822 + HTTP date 格式化/解析
///|
/// 格式化为 RFC2822 "Wed, 1 Jan 2026 00:00:00 +0000"。
pub fn DateTime::to_rfc2822(self : DateTime) -> String {
let ldt = self.naive_local()
let wd = ldt.weekday().to_int()
"\{weekday_abbr[wd]}, \{ldt.day().to_string()} \{month_abbr[ldt.month().to_int()]} \{ldt.year().to_string()} \{pad_zero(ldt.hour(), 2)}:\{pad_zero(ldt.minute(), 2)}:\{pad_zero(ldt.second(), 2)} \{format_offset_hhmm(self.off.offset_sec())}"
}
///|
/// 格式化为 HTTP date "Wed, 01 Jan 2026 00:00:00 GMT"(RFC 7231 IMF-fixdate)。
pub fn DateTime::to_http_date(self : DateTime) -> String {
let ldt = self.naive_local()
let wd = ldt.weekday().to_int()
"\{weekday_abbr[wd]}, \{pad_zero(ldt.day(), 2)} \{month_abbr[ldt.month().to_int()]} \{ldt.year().to_string()} \{pad_zero(ldt.hour(), 2)}:\{pad_zero(ldt.minute(), 2)}:\{pad_zero(ldt.second(), 2)} GMT"
}
///|
/// 跳过空格,返回新位置。
fn skip_ws(chars : Array[Char], p : Int32, n : Int32) -> Int32 {
let mut i = p
while i < n && chars[i] == ' ' {
i += 1
}
i
}
///|
/// 解析 1-2 位数字,返回 (值, 新位置)。
fn parse_1_2_digits(
chars : Array[Char],
p : Int32,
n : Int32,
) -> (Int64, Int32)? {
if p >= n || chars[p] < '0' || chars[p] > '9' {
return None
}
let d1 = (chars[p].to_int() - 48).to_int64()
let p1 = p + 1
if p1 < n && chars[p1] >= '0' && chars[p1] <= '9' {
let d2 = (chars[p1].to_int() - 48).to_int64()
Some((d1 * 10L + d2, p1 + 1))
} else {
Some((d1, p1))
}
}
///|
/// 解析月份缩写(Jan..Dec),返回 (月份1-12, 新位置)。
fn parse_month_abbr_2822(
chars : Array[Char],
p : Int32,
n : Int32,
) -> (Int64, Int32)? {
if p + 3 > n {
return None
}
let s = "\{chars[p]}\{chars[p + 1]}\{chars[p + 2]}"
for i in 1..<13 {
if month_abbr[i] == s {
return Some((i.to_int64(), p + 3))
}
}
None
}
///|
/// 判断字符是否字母
fn is_alpha_char(c : Char) -> Bool {
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
}
///|
/// 解析 RFC2822 日期时间,如 "Tue, 1 Jul 2003 10:52:37 +0200"。
/// 也接受无 weekday 形式 "1 Jul 2003 10:52:37 +0200"。
/// 返回 DateTime?(解析失败返回 None)。
pub fn DateTime::parse_rfc2822(s : String) -> DateTime? {
let chars = s.to_array()
let n = chars.length()
let mut p : Int32 = 0
p = skip_ws(chars, p, n)
// 跳过可选 weekday + ", "
if p + 4 < n &&
is_alpha_char(chars[p]) &&
is_alpha_char(chars[p + 1]) &&
is_alpha_char(chars[p + 2]) &&
chars[p + 3] == ',' {
p = skip_ws(chars, p + 4, n)
}
// 解析 day (1-2 位)
guard parse_1_2_digits(chars, p, n) is Some((day, p1)) else { return None }
p = skip_ws(chars, p1, n)
// 解析 month (3 字母)
guard parse_month_abbr_2822(chars, p, n) is Some((month, p2)) else {
return None
}
p = skip_ws(chars, p2, n)
// 解析 year (4 位)
guard parse_digits(chars, p, 4) is Some((year, p3)) else { return None }
p = skip_ws(chars, p3, n)
// 解析 HH:MM:SS
guard parse_digits(chars, p, 2) is Some((hour, p4)) else { return None }
if p4 >= n || chars[p4] != ':' {
return None
}
guard parse_digits(chars, p4 + 1, 2) is Some((min, p5)) else { return None }
if p5 >= n || chars[p5] != ':' {
return None
}
guard parse_digits(chars, p5 + 1, 2) is Some((sec, p6)) else { return None }
p = skip_ws(chars, p6, n)
// 解析偏移:GMT/UTC/UT 或 ±HHMM
let offset_sec : Int32 = if p < n && (chars[p] == 'G' || chars[p] == 'g') {
0
} else if p < n && (chars[p] == 'U' || chars[p] == 'u') {
0
} else if p < n && (chars[p] == '+' || chars[p] == '-') {
let sign : Int32 = if chars[p] == '+' { 1 } else { -1 }
guard parse_digits(chars, p + 1, 2) is Some((oh, p7)) else { return None }
guard parse_digits(chars, p7, 2) is Some((om, _)) else { return None }
sign * (oh.to_int() * 3600 + om.to_int() * 60)
} else {
return None
}
// 构造 DateTime
let naive = NaiveDateTime::make(year, month, day, hour, min, sec)
let utc_ts = naive.timestamp() - offset_sec.to_int64()
guard Tz::from_str("UTC") is Some(t) else { return None }
let off_span = @core.FixedTimespan::{ offset: offset_sec, name: "UTC", }
let off = TzOffset::make(t, off_span)
Some(DateTime::make(utc_ts, off))
}
///|
/// 解析 HTTP date "Wed, 15 Nov 1994 12:45:26 GMT"(RFC 7231)。
/// 返回 DateTime?(解析失败返回 None)。
pub fn DateTime::parse_http_date(s : String) -> DateTime? {
DateTime::parse_rfc2822(s)
}