// QN 请求编码:`YYYYMMDDhhmmsszzz`。
//
// 标准表里写 QN 是 20 位,但同一份标准的示例是 17 位
// (`20160801085857223`),现场设备也基本按 17 位实现。
// 这里按 17 位解析,同时容忍尾部多出的数字。

///|
pub(all) struct QnTime {
  year : Int32
  month : Int32
  day : Int32
  hour : Int32
  minute : Int32
  second : Int32
  millis : Int32
}

///|
pub fn QnTime::parse(qn : String) -> QnTime? {
  let cs = chars_of(trim_text(qn))
  if cs.length() < 17 {
    return None
  }
  let year = parse_uint(cs, 0, 4)
  let month = parse_uint(cs, 4, 2)
  let day = parse_uint(cs, 6, 2)
  let hour = parse_uint(cs, 8, 2)
  let minute = parse_uint(cs, 10, 2)
  let second = parse_uint(cs, 12, 2)
  let millis = parse_uint(cs, 14, 3)
  match (year, month, day, hour, minute, second, millis) {
    (Some(y), Some(mo), Some(d), Some(h), Some(mi), Some(s), Some(ms)) => {
      if mo < 1 || mo > 12 {
        return None
      }
      if d < 1 || d > 31 {
        return None
      }
      if h > 23 || mi > 59 || s > 60 {
        return None
      }
      Some({
        year: y,
        month: mo,
        day: d,
        hour: h,
        minute: mi,
        second: s,
        millis: ms,
      })
    }
    _ => None
  }
}

///|
/// 渲染成 `YYYY-MM-DD hh:mm:ss.zzz`。
pub fn QnTime::text(self : QnTime) -> String {
  "\{zero_pad(self.year, 4)}-\{zero_pad(self.month, 2)}-\{zero_pad(self.day, 2)} " +
  "\{zero_pad(self.hour, 2)}:\{zero_pad(self.minute, 2)}:\{zero_pad(self.second, 2)}.\{zero_pad(self.millis, 3)}"
}

///|
/// 由分段时间构造 QN。
pub fn QnTime::to_qn(self : QnTime) -> String {
  "\{zero_pad(self.year, 4)}\{zero_pad(self.month, 2)}\{zero_pad(self.day, 2)}" +
  "\{zero_pad(self.hour, 2)}\{zero_pad(self.minute, 2)}\{zero_pad(self.second, 2)}\{zero_pad(self.millis, 3)}"
}